TwitterImagePipeline/TIPImageStoreRequest.h (67 lines of code) (raw):
//
// TIPImageStoreRequest.h
// TwitterImagePipeline
//
// Created on 1/21/16.
// Copyright © 2020 Twitter. All rights reserved.
//
#import <Foundation/Foundation.h>
@protocol TIPImageStoreRequestHydrater;
NS_ASSUME_NONNULL_BEGIN
/** store options */
typedef NS_OPTIONS(NSInteger, TIPImageStoreOptions)
{
/** No options - default behavior */
TIPImageStoreNoOptions = 0,
/** Don't reset the expiry when accessed */
TIPImageStoreDoNotResetExpiryOnAccess = 1 << 0,
/**
When a matching `imageIdentifier` is fetched/stored that doesn't match this fetch's `imageURL`,
clear this store request's results from cache.
Useful for _"placeholder"_ fetches/stores that might have the same (or larger) dimensions as a
non-placeholder fetch/store.
*/
TIPImageStoreTreatAsPlaceholder = 1 << 1,
};
/**
`TIPImageStoreRequest` is a protocol that is to be implemented by an object for encapsulating the
relevant information for storing an image.
The store request requires the `imageURL` be provided, but also at least one of `image`,
`imageData` or `imageFilePath`.
# Providing multiple representations
`TIPImageStoreRequest` supports uploading multiple forms (`UIImage`, `NSData` and/or a path as an
`NSString`). This can provide optimizations in computation by reducing how many times the CPU
needs to decode/encode an image for the different representations that are stored in the caches.
## Logic for chosing the Memory Cache representation
* If `image` is provided, use that `UIImage`
* If `imageData` is provided, construct a `UIImage` with that `NSData` and use it
* If `imageFilePath` is provided, construct a `UIImage` with that file path and use it
## Logic for chosing the Disk Cache representation
* If `imageFilePath` is provided, copy that file to the disk cache
* If `imageData` is provided, write that data to the disk cache
* If `image` is provided, serialize the `image` to `NSData`, then write that data to the disk cache
*/
@protocol TIPImageStoreRequest <NSObject>
@required
/**
The `NSURL` of the image.
This doesn't necessarily have to match the _URL_ of where the image would be retrieved from over
the _Network_.
@note the `imageURL` is actually less important with storage than it is with retrieval.
The more important choice is what `imageIdentifier` to provide since that will be the primary
mechanism for matching image fetches to the internal cache(s). Not providing an `imageIdentifier`
(or `nil`) will fall back to using `[imageURL absoluteString]`.
*/
@property (nonatomic, readonly) NSURL *imageURL;
@optional
/**
The identifier for an image that is devoid of sizing related information.
This will be used for matching against existing cached images.
If not provided (or `nil`), `[imageURL absoluteString]` will be used instead.
*/
@property (nullable, nonatomic, readonly, copy) NSString *imageIdentifier;
/**
The duration that the image will live in the `TIPImagePipeline`'s internal cache(s).
Default == 30 days
*/
@property (nonatomic, readonly) NSTimeInterval timeToLive;
/**
The options for the store.
Default == `TIPImageStoreNoOptions`
*/
@property (nonatomic, readonly) TIPImageStoreOptions options;
@optional // one of the following is required
/**
The `UIImage` representation for storing.
Optionally providing the `imageType` property will specify how to encode the image to disk.
Takes precedence over `imageData` and `imageFilePath`.
*/
@property (nullable, nonatomic, readonly) UIImage *image; // TODO: refactor to be a `TIPImageContainer` instead of a `UIImage`
/**
The `NSData` of encoded image bytes for storing.
MUST provide the `imageDimensions` property too for the cache metadata.
Takes precedence over `imageFilePath`, but is subservient to `image`.
*/
@property (nullable, nonatomic, readonly) NSData *imageData;
/**
The `NSString` file path to the encoded image stored on disk.
MUST provide the `imageDimensions` property too for the cache metadata.
Is subservient to `image` and `imageData`.
*/
@property (nullable, nonatomic, readonly, copy) NSString *imageFilePath;
@optional // methods that accompany the above image methods
/**
The type of image to encode the provided `image` as, when stored to the disk cache.
Default == `nil`, which is the same as _automatic_
(currently: _GIF_ for animated images, _PNG_ for images w/ alpha, _JPEG_ with 85% quality for
everything else).
See `TIPImageTypes.h`
*/
@property (nonatomic, nullable, copy, readonly) NSString *imageType;
/**
The pixel dimensions (not points) of the image itself.
MUST be provided for either `imageData` or `imageFilePath` based store requests.
*/
@property (nonatomic, readonly) CGSize imageDimensions;
/**
The loop count if the `image` is animated.
Only applies to `image` based store requests.
Default == `0` (aka loop forever)
*/
@property (nonatomic, readonly) NSUInteger animationLoopCount;
/**
The durations (as `float` `NSNumber` objects) matching the frames of the `image` to be stored.
Only applies to `image` based store requests.
Default == calculated based on the `image` object's `duration` property
*/
@property (nullable, nonatomic, readonly, copy) NSArray<NSNumber *> *animationFrameDurations;
@optional // methods for extending work done in a store operation
/**
The hydrater to asynchronously prepare the request for the store operation to execute on.
See `TIPImageStoreRequestHydrater`.
Default == `nil`.
*/
@property (nullable, nonatomic, readonly) id<TIPImageStoreRequestHydrater> hydrater;
/**
A decoder config map for cases when we need to decode the image for memory cache storage
*/
@property (nullable, nonatomic, readonly, copy) NSDictionary<NSString *, id> *decoderConfigMap;
@end
///! Convenience function to get the imageIdentifier from a `TIPImageStoreRequest`
NS_INLINE NSString *TIPImageStoreRequestGetImageIdentifier(id<TIPImageStoreRequest> request)
{
NSString *imageIdentifier = nil;
if ([request respondsToSelector:@selector(imageIdentifier)]) {
imageIdentifier = request.imageIdentifier;
}
if (!imageIdentifier) {
imageIdentifier = request.imageURL.absoluteString;
}
return imageIdentifier;
}
/** `TIPImageStoreRequest` specifically for `UIImage` based store requests */
@protocol TIPImageObjectStoreRequest <TIPImageStoreRequest>
@required
/** Required */
@property (nullable, nonatomic, readonly) UIImage *image;
/** Required */
@property (nullable, nonatomic, copy, readonly) NSString *imageType;
@optional
/** Optional */
@property (nonatomic, readonly) NSUInteger animationLoopCount;
/** Optional */
@property (nullable, nonatomic, readonly, copy) NSArray<NSNumber *> *animationFrameDurations;
@end
/** `TIPImageStoreRequest` specifically for `NSData` based store requests */
@protocol TIPImageDataStoreRequest <TIPImageStoreRequest>
@required
/** Required */
@property (nullable, nonatomic, readonly) NSData *imageData;
/** Required */
@property (nonatomic, readonly) CGSize imageDimensions;
@end
/** `TIPImageStoreRequest` specifically for file path based store requests */
@protocol TIPImageFileStoreRequest <TIPImageStoreRequest>
@required
/** Required */
@property (nullable, nonatomic, readonly, copy) NSString *imageFilePath;
/** Required */
@property (nonatomic, readonly) CGSize imageDimensions;
@end
//! Completion callback to call when the _request_ being stored has hydrated
typedef void(^TIPImageStoreHydraterCompletionBlock)(id<TIPImageStoreRequest> __nullable request,
NSError *__nullable error);
/**
A protocol for extending the work that a store operation can perform on a `TIPImageStoreRequest`.
*/
@protocol TIPImageStoreRequestHydrater <NSObject>
@required
/**
Method to implement that offers asynchronous (or synchronous) time to prepare the store request for
execution on the image store operation.
Provide either an `NSError` to the _error_ argument, a new `TIPImageStoreRequest` to use or `nil`
to use the original _request_.
@note Hydration does _NOT_ cascade. That is, if the hydrater provides a new `TIPImageStoreRequest`
that has a `hydrater` value provided, that subsequent `hydrater` will be ignored.
@param request The original `TIPImageStoreRequest`
@param pipeline The `TIPImagePipeline` executing the storage
@param completion The completionBlock that must be called whenever hydration has completed.
*/
- (void)tip_hydrateImageStoreRequest:(id<TIPImageStoreRequest>)request
imagePipeline:(TIPImagePipeline *)pipeline
completion:(TIPImageStoreHydraterCompletionBlock)completion;
@end
NS_ASSUME_NONNULL_END