Skip to content

Commit

Permalink
Fast Image Cache 1.0
Browse files Browse the repository at this point in the history
Mallory Paine committed Oct 17, 2013
0 parents commit 3a86d17
Showing 54 changed files with 4,831 additions and 0 deletions.
22 changes: 22 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Mac OS X Finder
.DS_Store

# Xcode
build/*
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
*.xcworkspace
!default.xcworkspace
xcuserdata
profile
*.moved-aside
DerivedData

# Demo Images
FastImageCacheDemo/Demo Images/*.jpg
77 changes: 77 additions & 0 deletions FastImageCache/FICEntity.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
//
// FICEntity.h
// FastImageCache
//
// Copyright (c) 2013 Path, Inc.
// See LICENSE for full license agreement.
//

#import "FICImports.h"

typedef void (^FICEntityImageDrawingBlock)(CGContextRef context, CGSize contextSize);

/**
`FICEntity` is a protocol that classes interacting with the image cache must conform to. An entity uniquely identifies entries in image tables, which are instances of `<FICImageTable>`.
*/
@protocol FICEntity <NSObject>

@required

/**
A string that uniquely identifies this entity.
@discussion Within each image table, each entry is identified by an entity's UUID. Ideally, this value should never change for an entity. For example, if your entity class is a person
model, its UUID might be an API-assigned, unchanging, unique user ID. No matter how the properties of the person change, its user ID should never change.
*/
@property (nonatomic, copy, readonly) NSString *UUID;

/**
A string that uniquely identifies an entity's source image.
@discussion While `<UUID>` should be unchanging, a source image UUID might change. For example, if your entity class is a person model, its source image UUID might change every time the
person changes their profile photo. In this case, the source image UUID might be a hash of the profile photo URL (assuming each image is given a unique URL).
*/
@property (nonatomic, copy, readonly) NSString *sourceImageUUID;

/**
Returns the source image URL associated with a specific format name.
@param formatName The name of the image format that identifies which image table is requesting the source image.
@return A URL representing the requested source image.
@discussion Fast Image Cache operates on URLs when requesting source images. Typically, these URLs will point to remote image resources that must be downloaded from the Internet. While the
URL returned by this method must be a valid instance of `NSURL`, it does not need to point to an actual remote resource. The URL might point to a file path on disk or be composed of a custom
URL scheme of your choosing. The image cache's delegate is prompted to provide a source image for a particular entity and format name when it cannot find the requested image. It only uses the
URL returned by this method to key image cache requests. No network or file operations are performed by the image cache.
An example of when this method might return different source image URLs for the same entity is if you have defined several image formats for different thumbnail sizes and styles. For very
large thumbnails, the source image URL might be the original image. For smaller thumbnails, the source image URL might point to a downscaled version of the original image.
@see FICImageFormat
@see [FICImageCacheDelegate imageCache:wantsSourceImageForEntity:withFormatName:completionBlock:]
*/
- (NSURL *)sourceImageURLWithFormatName:(NSString *)formatName;

/**
Returns the drawing block for a specific image and format name.
@param image The cached image that represents this entity.
@param formatName The name of the image format that identifies which image table is requesting the source image.
@return The drawing block used to draw the image data to be stored in the image table.
The drawing block's type is defined as follows:
typedef void (^FICEntityImageDrawingBlock)(CGContextRef context, CGSize contextSize)
@discussion Each entity is responsible for drawing its own source image into the bitmap context provided by the image table that will store the image data. Often it is sufficient to simply
draw the image into the bitmap context. However, if you wish to apply any additional graphics processing to the source image before it is stored (such as clipping the image to a roundect rect),
you may use this block to do so.
@note This block will always be called from the serial dispatch queue used by the image cache.
*/
- (FICEntityImageDrawingBlock)drawingBlockForImage:(UIImage *)image withFormatName:(NSString *)formatName;

@end
32 changes: 32 additions & 0 deletions FastImageCache/FICImageCache+FICErrorLogging.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// FICImageCache+FICErrorLogging.h
// FastImageCache
//
// Copyright (c) 2013 Path, Inc.
// See LICENSE for full license agreement.
//

#import "FICImageCache.h"

/**
This category on `<FICImageCache>` simply exposes its private logging mechanism to other classes.
*/
@interface FICImageCache (FICErrorLogging)

///-----------------------------
/// @name Logging Error Messages
///-----------------------------

/**
Passes an error message to the image cache.
@param message A string representing the error message.
@discussion Rather than logging directly to standard output, Fast Image Cache classes pass all error logging to the shared `<FICImageCache>` instance. `<FICImageCache>` then allows its delegate to handle the
message.
@see [FICImageCacheDelegate imageCache:errorDidOccurWithMessage:]
*/
- (void)_logMessage:(NSString *)message;

@end
262 changes: 262 additions & 0 deletions FastImageCache/FICImageCache.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,262 @@
//
// FICImageCache.h
// FastImageCache
//
// Copyright (c) 2013 Path, Inc.
// See LICENSE for full license agreement.
//

#import "FICImports.h"
#import "FICImageFormat.h"
#import "FICEntity.h"

@protocol FICEntity;
@protocol FICImageCacheDelegate;

typedef void (^FICImageCacheCompletionBlock)(id <FICEntity> entity, NSString *formatName, UIImage *image);
typedef void (^FICImageRequestCompletionBlock)(UIImage *sourceImage);

/**
`FICImageCache` is the primary class for managing and interacting with the image cache. Applications using the image cache create one or more `<FICImageFormat>`
objects. These formats effectively act as logical groupings for image data stored in the image cache. An `<FICImageTable>` object is created for each format defined by
your application to allow for efficient storage and retrieval of image data. Image data is keyed off of objects conforming to the `<FICEntity>` protocol as well as an
image format name.
*/
@interface FICImageCache : NSObject

///----------------------------
/// @name Managing the Delegate
///----------------------------

/**
The delegate of the image cache.
@discussion The delegate is responsible for asynchronously providing the source image for an entity. Optionally, the delegate can require that all formats in a format
family for a particular entity be processed. Any errors that occur in the image cache are also communicated back to the delegate.
*/
@property(nonatomic, assign) id <FICImageCacheDelegate> delegate;

///---------------------------------------
/// @name Accessing the Shared Image Cache
///---------------------------------------

/**
Convenience accessor to retrieve a shared image cache instance.
*/
+ (instancetype)sharedImageCache;

///---------------------------------
/// @name Working with Image Formats
///---------------------------------

/**
Sets the image formats to be used by the image cache.
@param formats An array of `<FICImageFormat>` objects.
@note Once the image formats have been set, subsequent calls to this method will do nothing.
*/
- (void)setFormats:(NSArray *)formats;

/**
Returns an image format previously associated with the image cache.
@param formatName The name of the image format to return.
@return An image format with the name `formatName` or `nil` if no format with that name exists.
*/
- (FICImageFormat *)formatWithName:(NSString *)formatName;

/**
Returns all the image formats of the same family previously associated with the image cache.
@param family The name of the family of image formats to return.
@return An array of `<FICImageFormat>` objects whose family is `family` or `nil` if no format belongs to that family.
*/
- (NSArray *)formatsWithFamily:(NSString *)family;

///-----------------------------------------------
/// @name Storing, Retrieving, and Deleting Images
///-----------------------------------------------

/**
Manually sets the the image to be used by the image cache for a particular entity and format name.
@discussion Usually the image cache's delegate is responsible for lazily providing the source image for a given entity. This source image is then processed according
to the drawing block defined by an entity for a given image format. This method allows the sender to explicitly set the image data to be stored in the image cache.
After the image has been processed by the image cache, the completion block is called asynchronously on the main queue.
@param image The image to store in the image cache.
@param entity The entity that uniquely identifies the source image.
@param formatName The format name that uniquely identifies which image table to look in for the cached image.
@param completionBlock The completion block that is called after the image has been processed or if an error occurs.
The completion block's type is defined as follows:
typedef void (^FICImageCacheCompletionBlock)(id <FICEntity> entity, NSString *formatName, UIImage *image)
*/
- (void)setImage:(UIImage *)image forEntity:(id <FICEntity>)entity withFormatName:(NSString *)formatName completionBlock:(FICImageCacheCompletionBlock)completionBlock;

/**
Attempts to synchronously retrieve an image from the image cache.
@param entity The entity that uniquely identifies the source image.
@param formatName The format name that uniquely identifies which image table to look in for the cached image.
@param completionBlock The completion block that is called when the requested image is available or if an error occurs.
The completion block's type is defined as follows:
typedef void (^FICImageCacheCompletionBlock)(id <FICEntity> entity, NSString *formatName, UIImage *image)
If the requested image already exists in the image cache, then the completion block is immediately called synchronously on the current thread. If the requested image
does not already exist in the image cache, then the completion block will be called asynchronously on the main thread as soon as the requested image is available.
@return `YES` if the requested image already exists in the image case, `NO` if the image needs to be provided to the image cache by its delegate.
@discussion Even if you make a synchronous image retrieval request, if the image does not yet exist in the image cache, the delegate will be asked to provide a source
image, and it will be processed. This always occurs asynchronously. In this case, the return value from this method will be `NO`, and the image will be available in the
completion block.
@note You can always rely on the completion block being called. If an error occurs for any reason, the `image` parameter of the completion block will be `nil`. See
<[FICImageCacheDelegate imageCache:errorDidOccurWithMessage:]> for information about being notified when errors occur.
*/
- (BOOL)retrieveImageForEntity:(id <FICEntity>)entity withFormatName:(NSString *)formatName completionBlock:(FICImageCacheCompletionBlock)completionBlock;

/**
Asynchronously retrieves an image from the image cache.
@param entity The entity that uniquely identifies the source image.
@param formatName The format name that uniquely identifies which image table to look in for the cached image.
@param completionBlock The completion block that is called when the requested image is available or if an error occurs.
The completion block's type is defined as follows:
typedef void (^FICImageCacheCompletionBlock)(id <FICEntity> entity, NSString *formatName, UIImage *image)
Unlike its synchronous counterpart, this method will always call its completion block asynchronously on the main thread, even if the request image is already in the
image cache.
@return `YES` if the requested image already exists in the image case, `NO` if the image needs to be provided to the image cache by its delegate.
@note You can always rely on the completion block being called. If an error occurs for any reason, the `image` parameter of the completion block will be `nil`. See
<[FICImageCacheDelegate imageCache:errorDidOccurWithMessage:]> for information about being notified when errors occur.
@see [FICImageCache retrieveImageForEntity:withFormatName:completionBlock:]
*/
- (BOOL)asynchronouslyRetrieveImageForEntity:(id <FICEntity>)entity withFormatName:(NSString *)formatName completionBlock:(FICImageCacheCompletionBlock)completionBlock;

/**
Deletes an image from the image cache.
@param entity The entity that uniquely identifies the source image.
@param formatName The format name that uniquely identifies which image table to look in for the cached image.
*/
- (void)deleteImageForEntity:(id <FICEntity>)entity withFormatName:(NSString *)formatName;

///-----------------------------------
/// @name Checking for Image Existence
///-----------------------------------

/**
Returns whether or not an image exists in the image cache.
@param entity The entity that uniquely identifies the source image.
@param formatName The format name that uniquely identifies which image table to look in for the cached image.
@return `YES` if an image exists in the image cache for a given entity and format name. Otherwise, `NO`.
*/
- (BOOL)imageExistsForEntity:(id <FICEntity>)entity withFormatName:(NSString *)formatName;

///--------------------------------
/// @name Resetting the Image Cache
///--------------------------------

/**
Resets the image cache by deleting all image tables and their contents.
@note Resetting an image cache does not reset its image formats.
*/
- (void)reset;

@end

/**
`FICImageCacheDelegate` defines the required and optional actions that an image cache's delegate can perform.
*/
@protocol FICImageCacheDelegate <NSObject>

@required

/**
This method is called on the delegate when the image cache needs a source image.
@param imageCache The image cache that is requesting the source image.
@param entity The entity that uniquely identifies the source image.
@param formatName The format name that uniquely identifies which image table to look in for the cached image.
@param completionBlock The completion block that the receiver must call when it has a source image ready.
The completion block's type is defined as follows:
typedef void (^FICImageRequestCompletionBlock)(UIImage *sourceImage)
The completion block must always be called on the main thread.
@discussion A source image is usually the original, full-size image that represents an entity. This source image is processed for every unique format to create the
actual image data to be stored in the image cache. This method is an asynchronous data provider, so nothing is actually returned to the sender. Instead, the delegate's
implementation is expected to call the completion block once an image is available.
Fast Image Cache is architected under the typical design pattern whereby model objects provide a URL to certain image assets and allow the client to actually retrieve
the images via network requests only when needed. As a result, the implementation of this method will usually involve creating an asynchronous network request using
the URL returned by <[FICEntity sourceImageURLWithFormatName:]>, deserializing the image data when the request completes, and finally calling this method's completion
block to provide the image cache with the source image.
*/
- (void)imageCache:(FICImageCache *)imageCache wantsSourceImageForEntity:(id <FICEntity>)entity withFormatName:(NSString *)formatName completionBlock:(FICImageRequestCompletionBlock)completionBlock;

@optional

/**
This method is called on the delegate to determine whether or not all formats in a family should be processed right now.
@note If this method is not implemented by the delegate, the default value is `YES`.
@param imageCache The image cache that is requesting the source image.
@param formatFamily The name of a format family.
@param entity The entity that uniquely identifies the source image.
@return `YES` if all formats in a format family should be processed. Otherwise, `NO`.
@discussion This method is called whenever new image data is stored in the image cache. Because format families are used to group multiple different formats together,
typically the delegate will want to return `YES` here so that other formats in the same family can be processed.
For example, if your image cache has defined several different thumbnail sizes and styles for a person model, and if a person changes their profile photo, you would
want every thumbnail size and style is updated with the new source image.
*/
- (BOOL)imageCache:(FICImageCache *)imageCache shouldProcessAllFormatsInFamily:(NSString *)formatFamily forEntity:(id <FICEntity>)entity;

/**
This method is called on the delegate whenever the image cache has an error message to log.
@param imageCache The image cache that is requesting the source image.
@param errorMessage The error message generated by the image cache.
@discussion Fast Image Cache will not explicitly log any messages to standard output. Instead, it allows the delegate to handle (or ignore) any error output.
*/
- (void)imageCache:(FICImageCache *)imageCache errorDidOccurWithMessage:(NSString *)errorMessage;

@end
Loading

0 comments on commit 3a86d17

Please sign in to comment.