TwitterImagePipeline/Project/TIPImageCacheEntry.m (188 lines of code) (raw):

// // TIPImageCacheEntry.m // TwitterImagePipeline // // Created on 3/6/15. // Copyright (c) 2015 Twitter. All rights reserved. // #import "TIP_Project.h" #import "TIPImageCacheEntry.h" #import "TIPImageUtils.h" #import "TIPPartialImage.h" NS_ASSUME_NONNULL_BEGIN #pragma mark - Private Declarations @interface TIPImageCacheEntryContext () - (instancetype)initWithCacheEntryContext:(TIPImageCacheEntryContext *)context; @end @interface TIPImageCacheEntry () @property (nonatomic, nullable) NSData *completeImageData; @property (nonatomic, nullable, copy) NSString *completeImageFilePath; - (instancetype)initWithCacheEntry:(TIPImageCacheEntry *)cacheEntry; @end @interface TIPImageMemoryCacheEntry () @property (nonatomic, readonly) NSUInteger memoryCost; @end @interface TIPImageDiskCacheEntry () @property (nonatomic, readonly, copy, nullable) NSString *safeIdentifier; @property (nonatomic) NSUInteger completeFileSize; @property (nonatomic) NSUInteger partialFileSize; @end #pragma mark - Implementations @implementation TIPImageCacheEntryContext - (instancetype)initWithCacheEntryContext:(TIPImageCacheEntryContext *)context { if (self = [super init]) { _updateExpiryOnAccess = context.updateExpiryOnAccess; _treatAsPlaceholder = context.treatAsPlaceholder; _TTL = context.TTL; _URL = context.URL; _lastAccess = context.lastAccess; _dimensions = context.dimensions; _animated = context.animated; } return self; } - (id)copyWithZone:(nullable NSZone *)zone { TIPImageCacheEntryContext *context = [[[self class] allocWithZone:zone] initWithCacheEntryContext:self]; return context; } @end @implementation TIPCompleteImageEntryContext - (instancetype)initWithCacheEntryContext:(TIPImageCacheEntryContext *)context { if (self = [super initWithCacheEntryContext:context]) { if ([context respondsToSelector:@selector(imageType)]) { _imageType = [(TIPCompleteImageEntryContext *)context imageType]; } } return self; } @end @implementation TIPPartialImageEntryContext - (instancetype)initWithCacheEntryContext:(TIPImageCacheEntryContext *)context { if (self = [super initWithCacheEntryContext:context]) { if ([context respondsToSelector:@selector(expectedContentLength)]) { _expectedContentLength = [(TIPPartialImageEntryContext *)context expectedContentLength]; } if ([context respondsToSelector:@selector(lastModified)]) { _lastModified = [[(TIPPartialImageEntryContext *)context lastModified] copy]; } } return self; } @end @implementation TIPImageCacheEntry - (instancetype)initWithCacheEntry:(TIPImageCacheEntry *)cacheEntry { if (self = [super init]) { _identifier = [cacheEntry.identifier copy]; _partialImage = cacheEntry.partialImage; _partialImageContext = [cacheEntry.partialImageContext copy]; _completeImage = cacheEntry.completeImage; _completeImageContext = [cacheEntry.completeImageContext copy]; } return self; } - (id)copyWithZone:(nullable NSZone *)zone { TIPImageCacheEntry *copy = [[[self class] allocWithZone:zone] initWithCacheEntry:self]; return copy; } - (BOOL)isValid:(BOOL)mustHaveSomeImage { if (!_identifier) { return NO; } if (!_partialImage ^ !_partialImageContext) { return NO; } if (!_completeImage ^ !_completeImageContext) { return NO; } return !mustHaveSomeImage || (_partialImage || _completeImage); } - (BOOL)shouldAccessMoveLRUEntryToHead { return self.completeImageContext.updateExpiryOnAccess || self.partialImageContext.updateExpiryOnAccess; } - (NSString *)LRUEntryIdentifier { return self.identifier; } @end @implementation TIPImageCacheEntry (Access) - (nullable NSDate *)mostRecentAccess { NSDate *completeDate = _completeImageContext.lastAccess; NSDate *partialDate = _partialImageContext.lastAccess; if (!completeDate) { return partialDate; } else if (!partialDate) { return completeDate; } return [completeDate laterDate:partialDate]; } @end @implementation TIPImageMemoryCacheEntry { NSUInteger _memoryCost; } @synthesize memoryCost = _memoryCost; - (void)setCompleteImage:(nullable TIPImageContainer *)completeImage { super.completeImage = completeImage; _memoryCost = 0; } - (void)setCompleteImageFilePath:(nullable NSString *)completeImageFilePath { TIPAssert(NO && "Should not be used!"); } - (void)setCompleteImageContext:(nullable TIPCompleteImageEntryContext *)completeImageContext { super.completeImageContext = completeImageContext; _memoryCost = 0; } - (void)setPartialImage:(nullable TIPPartialImage *)partialImage { super.partialImage = partialImage; _memoryCost = 0; } - (void)setPartialImageContext:(nullable TIPPartialImageEntryContext *)partialImageContext { super.partialImageContext = partialImageContext; _memoryCost = 0; } - (NSUInteger)memoryCost { if (!_memoryCost) { _memoryCost += self.completeImageData.length; _memoryCost += self.partialImage.byteCount; } return _memoryCost; } @end @implementation TIPImageDiskCacheEntry @synthesize safeIdentifier = _safeIdentifier; - (void)setIdentifier:(nullable NSString *)identifier { super.identifier = identifier; _safeIdentifier = nil; } - (nullable NSString *)safeIdentifier { if (!_safeIdentifier) { _safeIdentifier = TIPSafeFromRaw(self.identifier); } return _safeIdentifier; } - (NSString *)LRUEntryIdentifier { return self.safeIdentifier; } - (instancetype)initWithCacheEntry:(TIPImageCacheEntry *)cacheEntry { if (self = [super initWithCacheEntry:cacheEntry]) { if ([cacheEntry isKindOfClass:[TIPImageDiskCacheEntry class]]) { _completeFileSize = [(TIPImageDiskCacheEntry *)cacheEntry completeFileSize]; _partialFileSize = [(TIPImageDiskCacheEntry *)cacheEntry partialFileSize]; } } return self; } @end NS_ASSUME_NONNULL_END