在线时间:8:00-16:00
迪恩网络APP
随时随地掌握行业动态
扫描二维码
关注迪恩网络微信公众号
开源软件名称:path/FastImageCache开源软件地址:https://github.com/path/FastImageCache开源编程语言:Objective-C 99.9%开源软件介绍:Fast Image Cache is an efficient, persistent, and—above all—fast way to store and retrieve images in your iOS application. Part of any good iOS application's user experience is fast, smooth scrolling, and Fast Image Cache helps make this easier. A significant burden on performance for graphics-rich applications like Path is image loading. The traditional method of loading individual images from disk is just too slow, especially while scrolling. Fast Image Cache was created specifically to solve this problem. Table of Contents
Version History
What Fast Image Cache Does
How Fast Image Cache WorksIn order to understand how Fast Image Cache works, it's helpful to understand a typical scenario encountered by many applications that work with images. The ScenarioiOS applications, especially those in the social networking space, often have many images to display at once, such as user photos. The intuitive, traditional approach is to request image data from an API, process the original images to create the desired sizes and styles, and store these processed images on the device. Later, when an application needs to display these images, they are loaded from disk into memory and displayed in an image view or are otherwise rendered to the screen. The ProblemIt turns out that the process of going from compressed, on-disk image data to a rendered Core Animation layer that the user can actually see is very expensive. As the number of images to be displayed increases, this cost easily adds up to a noticeable degradation in frame rate. And scrollable views further exacerbate the situation because content can change rapidly, requiring fast processing time to maintain a smooth 60FPS.1 Consider the workflow that occurs when loading an image from disk and displaying it on screen:
These costs can easily accumulate and kill perceived application performance. Especially while scrolling, users are presented with an unsatisfying user experience that is not in line with the the overall iOS experience. 1 2 The documentation for 3 As of iOS 7, Apple does not make their hardware JPEG decoder available for third-party applications to use. As a result, only a slower, software decoder is used for this step. The SolutionFast Image Cache minimizes (or avoids entirely) much of the work described above using a variety of techniques: Mapped MemoryAt the heart of how Fast Image Cache works are image tables. Image tables are similar to sprite sheets, often used in 2D gaming. An image table packs together images of the same dimensions into a single file. This file is opened once and is left open for reading and writing for as long as an application remains in memory. Image tables use the When a request is made to the image cache to return a specific image, the image table finds (in constant time) the location of the desired image data in the file it maintains. That region of file data is mapped into memory, and a new When the returned In like manner, when image data is being stored in an image table, a memory-mapped bitmap context is created. Along with the original image, this context is passed to an image table's corresponding entity object. This object is responsible for drawing the image into the current context, optionally further configuring the context (e.g., clipping the context to a rounded rect) or doing any additional drawing (e.g., drawing an overlay image atop the original image). Uncompressed Image DataIn order to avoid expensive image decompression operations, image tables store uncompressed image data in their files. If a source image is compressed, it must first be decompressed for the image table to work with it. This is a one-time cost. Furthermore, it is possible to utilize image format families to perform this decompression exactly once for a collection of similar image formats. There are obvious consequences to this approach, however. Uncompressed image data requires more disk space, and the difference between compressed and uncompressed file sizes can be significant, especially for image formats like JPEG. For this reason, Fast Image Cache works best with smaller images, although there is no API restriction that enforces this. Byte AlignmentFor high-performance scrolling, it is critical that Core Animation is able to use an image without first having to create a copy. One of the reasons Core Animation would create a copy of an image is improper byte-alignment of the image's underlying ConsiderationsImage Table SizeImage tables are configured by image formats, which specify (among other things) the maximum number of entries (i.e., individual images) an image table can have. This is to prevent the size of an image table file from growing arbitrarily. Image tables allocate 4 bytes per pixel, so the maximum space occupied by an image table file can be determined as follows:
Applications using Fast Image Cache should carefully consider how many images each image table should contain. When a new image is stored in an image table that is already full, it will replace the least-recently-accessed image. Image Table TransienceImage table files are stored in the user's caches directory in a subdirectory called
Source Image PersistenceFast Image Cache does not persist the original source images processed by entities to create the image data stored in its image tables. For example, if an original image is resized by an entity to create a thumbnail to be stored in an image table, it is the application's responsibility to either persist the original image or be able to retrieve or recreate it again. Image format families can be specified to efficiently make use of a single source image. See Working with Image Format Families for more information. Data ProtectionIn iOS 4, Apple introduced data protection. When a user's device is locked or turned off, the disk is encrypted. Files written to disk are protected by default, although applications can manually specify the data protection mode for each file it manages. With the advent of new background modes in iOS 7, applications can now execute in the background briefly even while the device is locked. As a result, data protection can cause issues if applications attempt to access files that are encrypted. Fast Image Cache allows each image format to specify the data protection mode used when creating its backing image table file. Be aware that enabling data protection for image table files means that Fast Image Cache might not be able to read or write image data from or to these files when the disk is encrypted. RequirementsFast Image Cache requires iOS 6.0 or greater and relies on the following frameworks:
The Getting StartedIntegrating Fast Image CacheCocoaPodsFor easy project integration, Fast Image Cache is available as a CocoaPod. Manually
Initial ConfigurationBefore the image cache can be used, it needs to be configured. This must occur each launch, so the application delegate might be a good place to do this. Creating Image FormatsEach image format corresponds to an image table that the image cache will use. Image formats that can use the same source image to render the images they store in their image tables should belong to the same image format family. See Image Table Size for more information about how to determine an appropriate maximum count. static NSString *XXImageFormatNameUserThumbnailSmall = @"com.mycompany.myapp.XXImageFormatNameUserThumbnailSmall";
static NSString *XXImageFormatNameUserThumbnailMedium = @"com.mycompany.myapp.XXImageFormatNameUserThumbnailMedium";
static NSString *XXImageFormatFamilyUserThumbnails = @"com.mycompany.myapp.XXImageFormatFamilyUserThumbnails";
FICImageFormat *smallUserThumbnailImageFormat = [[FICImageFormat alloc] init];
smallUserThumbnailImageFormat.name = XXImageFormatNameUserThumbnailSmall;
smallUserThumbnailImageFormat.family = XXImageFormatFamilyUserThumbnails;
smallUserThumbnailImageFormat.style = FICImageFormatStyle16BitBGR;
smallUserThumbnailImageFormat.imageSize = CGSizeMake(50, 50);
smallUserThumbnailImageFormat.maximumCount = 250;
smallUserThumbnailImageFormat.devices = FICImageFormatDevicePhone;
smallUserThumbnailImageFormat.protectionMode = FICImageFormatProtectionModeNone;
FICImageFormat *mediumUserThumbnailImageFormat = [[FICImageFormat alloc] init];
mediumUserThumbnailImageFormat.name = XXImageFormatNameUserThumbnailMedium;
mediumUserThumbnailImageFormat.family = XXImageFormatFamilyUserThumbnails;
mediumUserThumbnailImageFormat.style = FICImageFormatStyle32BitBGRA;
mediumUserThumbnailImageFormat.imageSize = CGSizeMake(100, 100);
mediumUserThumbnailImageFormat.maximumCount = 250;
mediumUserThumbnailImageFormat.devices = FICImageFormatDevicePhone;
mediumUserThumbnailImageFormat.protectionMode = FICImageFormatProtectionModeNone;
NSArray *imageFormats = @[smallUserThumbnailImageFormat, mediumUserThumbnailImageFormat]; An image format's style effectively determines the bit depth of the images stored in an image table. The following styles are currently available:
If the source images lack transparency (e.g., JPEG images), then better Core Animation performance can be achieved by using 32-bit color with no alpha component. If the source images have little color detail, or if the image format's image size is relatively small, it may be sufficient to use 16-bit color with little or no perceptible loss of quality. This results in smaller image table files stored on disk. Configuring the Image CacheOnce one or more image formats have been defined, they need to be assigned to the image cache. Aside from assigning the image cache's delegate, there is nothing further that can be configured on the image cache itself. FICImageCache *sharedImageCache = [FICImageCache sharedImageCache];
sharedImageCache.delegate = self;
sharedImageCache.formats = imageFormats; Creating EntitiesEntities are objects that conform to the @interface XXUser : NSObject <FICEntity>
@property (nonatomic, assign, getter = isActive) BOOL active;
@property (nonatomic, copy) NSString *userID;
@property (nonatomic, copy) NSURL *userPhotoURL;
@end Here is an example implementation of the - (NSString *)UUID {
CFUUIDBytes UUIDBytes = FICUUIDBytesFromMD5HashOfString(_userID);
NSString *UUID = FICStringWithUUIDBytes(UUIDBytes);
return UUID;
}
- (NSString *)sourceImageUUID {
CFUUIDBytes sourceImageUUIDBytes = FICUUIDBytesFromMD5HashOfString([_userPhotoURL absoluteString]);
NSString *sourceImageUUID = FICStringWithUUIDBytes(sourceImageUUIDBytes);
return sourceImageUUID;
}
- (NSURL *)sourceImageURLWithFormatName:(NSString *)formatName {
return _sourceImageURL;
}
- (FICEntityImageDrawingBlock)drawingBlockForImage:(UIImage *)image withFormatName:(NSString *)formatName {
FICEntityImageDrawingBlock drawingBlock = ^(CGContextRef context, CGSize contextSize) {
CGRect contextBounds = CGRectZero;
contextBounds.size = contextSize;
CGContextClearRect(context, contextBounds);
// Clip medium thumbnails so they have rounded corners
if ([formatName isEqualToString:XXImageFormatNameUserThumbnailMedium]) {
UIBezierPath clippingPath = [self _clippingPath];
[clippingPath addClip];
}
UIGraphicsPushContext(context);
[image drawInRect:contextBounds];
UIGraphicsPopContext();
};
return drawingBlock;
} Ideally, an entity's An entity's
When the image cache is asked to provide an image for a particular entity and format name, the entity is responsible for providing a URL. The URL need not even point to an actual resource—e.g., the URL might be constructed of a custom URL-scheme—, but it must be a valid URL. The image cache uses these URLs merely to keep track of which image requests are already in flight; multiple requests to the image cache for the same image are handled correctly without any wasted effort. The choice to use URLs as a basis for keying image cache requests actually complements many real-world application designs whereby URLs to image resources (rather than the images themselves) are included with server-provided model data.
Finally, once the source image is available, the entity is asked to provide a drawing block. The image table that will store the final image sets up a file-mapped bitmap context and invokes the entity's drawing block. This makes it convenient for each entity to decide how to process the source image for particular image formats. Requesting Images from the Image CacheFast Image Cache works under the on-demand, lazy-loading design pattern common to Cocoa. XXUser *user = [self _currentUser];
NSString *formatName = XXImageFormatNameUserThumbnailSmall;
FICImageCacheCompletionBlock completionBlock = ^(id <FICEntity> entity, NSString *formatName, UIImage *image) {
_imageView.image = image;
[_imageView.layer addAnimation:[CATransition animation] forKey:kCATransition];
};
BOOL imageExists = [sharedImageCache retrieveImageForEntity:user withFormatName:formatName completionBlock:completionBlock];
if (imageExists == NO) {
_imageView.image = [self _userPlaceholderImage];
} There are a few things to note here.
Providing Source Images to the Image CacheThere are two ways to provide source images to the image cache.
Canceling Source Image RequestsIf an image request is already in progress, it can be cancelled: // We scrolled up far enough that the image we requested in no longer visible; cancel the request
XXUser *user = [self _currentUser];
NSString *formatName = XXImageFormatNameUserThumbnailSmall;
[sharedImageCache |
2023-10-27
2022-08-15
2022-08-17
2022-09-23
2022-08-13
请发表评论