2015-03-23 22:07:33 +00:00
|
|
|
/**
|
|
|
|
* Copyright (c) 2015-present, Facebook, Inc.
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* This source code is licensed under the BSD-style license found in the
|
|
|
|
* LICENSE file in the root directory of this source tree. An additional grant
|
|
|
|
* of patent rights can be found in the PATENTS file in the same directory.
|
|
|
|
*/
|
2015-03-11 02:11:28 +00:00
|
|
|
|
2015-07-14 11:06:17 +00:00
|
|
|
#import <UIKit/UIKit.h>
|
2015-03-11 02:11:28 +00:00
|
|
|
|
2015-07-27 15:48:31 +00:00
|
|
|
#import "RCTBridge.h"
|
2015-09-02 15:25:10 +00:00
|
|
|
#import "RCTURLRequestHandler.h"
|
2016-01-20 19:03:22 +00:00
|
|
|
#import "RCTResizeMode.h"
|
2015-07-27 15:48:31 +00:00
|
|
|
|
2015-07-27 20:46:59 +00:00
|
|
|
typedef void (^RCTImageLoaderProgressBlock)(int64_t progress, int64_t total);
|
2016-09-21 19:11:19 +00:00
|
|
|
typedef void (^RCTImageLoaderPartialLoadBlock)(UIImage *image);
|
2015-09-04 11:35:44 +00:00
|
|
|
typedef void (^RCTImageLoaderCompletionBlock)(NSError *error, UIImage *image);
|
2016-07-11 20:23:40 +00:00
|
|
|
typedef dispatch_block_t RCTImageLoaderCancellationBlock;
|
2015-07-15 20:17:13 +00:00
|
|
|
|
2016-08-02 05:00:56 +00:00
|
|
|
/**
|
|
|
|
* Provides an interface to use for providing a image caching strategy.
|
|
|
|
*/
|
|
|
|
@protocol RCTImageCache <NSObject>
|
|
|
|
|
|
|
|
- (UIImage *)imageForUrl:(NSString *)url
|
|
|
|
size:(CGSize)size
|
|
|
|
scale:(CGFloat)scale
|
|
|
|
resizeMode:(RCTResizeMode)resizeMode
|
|
|
|
responseDate:(NSString *)responseDate;
|
|
|
|
|
|
|
|
- (void)addImageToCache:(UIImage *)image
|
|
|
|
URL:(NSString *)url
|
|
|
|
size:(CGSize)size
|
|
|
|
scale:(CGFloat)scale
|
|
|
|
resizeMode:(RCTResizeMode)resizeMode
|
|
|
|
responseDate:(NSString *)responseDate;
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2015-09-04 11:35:44 +00:00
|
|
|
@interface UIImage (React)
|
|
|
|
|
|
|
|
@property (nonatomic, copy) CAKeyframeAnimation *reactKeyframeAnimation;
|
|
|
|
|
|
|
|
@end
|
|
|
|
|
2015-09-02 15:25:10 +00:00
|
|
|
@interface RCTImageLoader : NSObject <RCTBridgeModule, RCTURLRequestHandler>
|
2015-05-11 20:08:39 +00:00
|
|
|
|
2016-02-16 20:41:20 +00:00
|
|
|
/**
|
|
|
|
* The maximum number of concurrent image loading tasks. Loading and decoding
|
|
|
|
* images can consume a lot of memory, so setting this to a higher value may
|
|
|
|
* cause memory to spike. If you are seeing out-of-memory crashes, try reducing
|
|
|
|
* this value.
|
|
|
|
*/
|
|
|
|
@property (nonatomic, assign) NSUInteger maxConcurrentLoadingTasks;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The maximum number of concurrent image decoding tasks. Decoding large
|
|
|
|
* images can be especially CPU and memory intensive, so if your are decoding a
|
|
|
|
* lot of large images in your app, you may wish to adjust this value.
|
|
|
|
*/
|
|
|
|
@property (nonatomic, assign) NSUInteger maxConcurrentDecodingTasks;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Decoding large images can use a lot of memory, and potentially cause the app
|
|
|
|
* to crash. This value allows you to throttle the amount of memory used by the
|
|
|
|
* decoder independently of the number of concurrent threads. This means you can
|
|
|
|
* still decode a lot of small images in parallel, without allowing the decoder
|
|
|
|
* to try to decompress multiple huge images at once. Note that this value is
|
|
|
|
* only a hint, and not an indicator of the total memory used by the app.
|
|
|
|
*/
|
|
|
|
@property (nonatomic, assign) NSUInteger maxConcurrentDecodingBytes;
|
|
|
|
|
2015-05-11 20:08:39 +00:00
|
|
|
/**
|
2015-07-27 15:48:31 +00:00
|
|
|
* Loads the specified image at the highest available resolution.
|
2015-10-20 12:00:50 +00:00
|
|
|
* Can be called from any thread, will call back on an unspecified thread.
|
2015-05-11 20:08:39 +00:00
|
|
|
*/
|
2016-06-01 17:32:20 +00:00
|
|
|
- (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)imageURLRequest
|
|
|
|
callback:(RCTImageLoaderCompletionBlock)callback;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* As above, but includes target `size`, `scale` and `resizeMode`, which are used to
|
|
|
|
* select the optimal dimensions for the loaded image. The `clipped` option
|
|
|
|
* controls whether the image will be clipped to fit the specified size exactly,
|
|
|
|
* or if the original aspect ratio should be retained.
|
2016-09-21 19:11:19 +00:00
|
|
|
* `partialLoadBlock` is meant for custom image loaders that do not ship with the core RN library.
|
|
|
|
* It is meant to be called repeatedly while loading the image as higher quality versions are decoded,
|
|
|
|
* for instance with progressive JPEGs.
|
2016-06-01 17:32:20 +00:00
|
|
|
*/
|
|
|
|
- (RCTImageLoaderCancellationBlock)loadImageWithURLRequest:(NSURLRequest *)imageURLRequest
|
|
|
|
size:(CGSize)size
|
|
|
|
scale:(CGFloat)scale
|
|
|
|
clipped:(BOOL)clipped
|
|
|
|
resizeMode:(RCTResizeMode)resizeMode
|
|
|
|
progressBlock:(RCTImageLoaderProgressBlock)progressBlock
|
2016-09-21 19:11:19 +00:00
|
|
|
partialLoadBlock:(RCTImageLoaderPartialLoadBlock)partialLoadBlock
|
2016-06-01 17:32:20 +00:00
|
|
|
completionBlock:(RCTImageLoaderCompletionBlock)completionBlock;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Finds an appropriate image decoder and passes the target `size`, `scale` and
|
|
|
|
* `resizeMode` for optimal image decoding. The `clipped` option controls
|
|
|
|
* whether the image will be clipped to fit the specified size exactly, or
|
|
|
|
* if the original aspect ratio should be retained. Can be called from any
|
|
|
|
* thread, will call callback on an unspecified thread.
|
|
|
|
*/
|
|
|
|
- (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData
|
|
|
|
size:(CGSize)size
|
|
|
|
scale:(CGFloat)scale
|
|
|
|
clipped:(BOOL)clipped
|
|
|
|
resizeMode:(RCTResizeMode)resizeMode
|
|
|
|
completionBlock:(RCTImageLoaderCompletionBlock)completionBlock;
|
2015-03-11 02:11:28 +00:00
|
|
|
|
2015-07-14 11:06:17 +00:00
|
|
|
/**
|
2016-06-01 17:32:20 +00:00
|
|
|
* Get image size, in pixels. This method will do the least work possible to get
|
|
|
|
* the information, and won't decode the image if it doesn't have to.
|
2015-07-14 11:06:17 +00:00
|
|
|
*/
|
2016-06-01 17:32:20 +00:00
|
|
|
- (RCTImageLoaderCancellationBlock)getImageSizeForURLRequest:(NSURLRequest *)imageURLRequest
|
|
|
|
block:(void(^)(NSError *error, CGSize size))completionBlock;
|
|
|
|
|
2016-08-02 05:00:56 +00:00
|
|
|
/**
|
|
|
|
* Allows developers to set their own caching implementation for
|
|
|
|
* decoded images as long as it conforms to the RCTImageCacheDelegate
|
|
|
|
* protocol. This method should be called in bridgeDidInitializeModule.
|
|
|
|
*/
|
|
|
|
- (void)setImageCache:(id<RCTImageCache>)cache;
|
|
|
|
|
2016-06-01 17:32:20 +00:00
|
|
|
@end
|
|
|
|
|
2015-07-27 15:48:31 +00:00
|
|
|
@interface RCTBridge (RCTImageLoader)
|
|
|
|
|
|
|
|
/**
|
|
|
|
* The shared image loader instance
|
|
|
|
*/
|
|
|
|
@property (nonatomic, readonly) RCTImageLoader *imageLoader;
|
|
|
|
|
2015-09-02 15:25:10 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
/**
|
2015-10-19 16:04:54 +00:00
|
|
|
* Provides the interface needed to register an image loader. Image data
|
2015-09-02 15:25:10 +00:00
|
|
|
* loaders are also bridge modules, so should be registered using
|
|
|
|
* RCT_EXPORT_MODULE().
|
|
|
|
*/
|
|
|
|
@protocol RCTImageURLLoader <RCTBridgeModule>
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Indicates whether this data loader is capable of processing the specified
|
|
|
|
* request URL. Typically the handler would examine the scheme/protocol of the
|
|
|
|
* URL to determine this.
|
|
|
|
*/
|
|
|
|
- (BOOL)canLoadImageURL:(NSURL *)requestURL;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Send a network request to load the request URL. The method should call the
|
|
|
|
* progressHandler (if applicable) and the completionHandler when the request
|
|
|
|
* has finished. The method should also return a cancellation block, if
|
|
|
|
* applicable.
|
|
|
|
*/
|
2015-10-19 16:04:54 +00:00
|
|
|
- (RCTImageLoaderCancellationBlock)loadImageForURL:(NSURL *)imageURL
|
|
|
|
size:(CGSize)size
|
|
|
|
scale:(CGFloat)scale
|
2016-01-20 19:03:22 +00:00
|
|
|
resizeMode:(RCTResizeMode)resizeMode
|
2015-10-19 16:04:54 +00:00
|
|
|
progressHandler:(RCTImageLoaderProgressBlock)progressHandler
|
2016-09-21 19:11:19 +00:00
|
|
|
partialLoadHandler:(RCTImageLoaderPartialLoadBlock)partialLoadHandler
|
2015-10-19 16:04:54 +00:00
|
|
|
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler;
|
2015-09-02 15:25:10 +00:00
|
|
|
|
|
|
|
@optional
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If more than one RCTImageURLLoader responds YES to `-canLoadImageURL:`
|
2015-10-19 16:04:54 +00:00
|
|
|
* then `loaderPriority` is used to determine which one to use. The loader
|
2015-09-02 15:25:10 +00:00
|
|
|
* with the highest priority will be selected. Default priority is zero. If
|
2015-10-19 16:04:54 +00:00
|
|
|
* two or more valid loaders have the same priority, the selection order is
|
2015-09-02 15:25:10 +00:00
|
|
|
* undefined.
|
|
|
|
*/
|
2015-10-19 16:04:54 +00:00
|
|
|
- (float)loaderPriority;
|
2015-09-02 15:25:10 +00:00
|
|
|
|
2016-07-21 14:45:54 +00:00
|
|
|
/**
|
|
|
|
* If the loader must be called on the serial url cache queue, and whether the completion
|
|
|
|
* block should be dispatched off the main thread. If this is NO, the loader will be
|
|
|
|
* called from the main queue. Defaults to YES.
|
|
|
|
*
|
|
|
|
* Use with care: disabling scheduling will reduce RCTImageLoader's ability to throttle
|
|
|
|
* network requests.
|
|
|
|
*/
|
|
|
|
- (BOOL)requiresScheduling;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* If images loaded by the loader should be cached in the decoded image cache.
|
|
|
|
* Defaults to YES.
|
|
|
|
*/
|
|
|
|
- (BOOL)shouldCacheLoadedImages;
|
|
|
|
|
2015-09-02 15:25:10 +00:00
|
|
|
@end
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Provides the interface needed to register an image decoder. Image decoders
|
|
|
|
* are also bridge modules, so should be registered using RCT_EXPORT_MODULE().
|
|
|
|
*/
|
2015-10-19 16:04:54 +00:00
|
|
|
@protocol RCTImageDataDecoder <RCTBridgeModule>
|
2015-09-02 15:25:10 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Indicates whether this handler is capable of decoding the specified data.
|
|
|
|
* Typically the handler would examine some sort of header data to determine
|
|
|
|
* this.
|
|
|
|
*/
|
|
|
|
- (BOOL)canDecodeImageData:(NSData *)imageData;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Decode an image from the data object. The method should call the
|
|
|
|
* completionHandler when the decoding operation has finished. The method
|
|
|
|
* should also return a cancellation block, if applicable.
|
Change RCTImageLoader's Cache System to default NSURLRequest's cache system
Summary:
Before this PR, ```RCTImageLodaer```'s Cache was too big(200MB on disk) and It doesn't work with HTTP Cache-Control header. So to provide dynamic image, the users must have to add random value on url( ex. adding current date) to avoid cache.
So I change that cache system to default ```NSURLRequest```'s cache system, which is well-working with HTTP specs. As the discussion on this issue #7571 , making custom cache policy processor is not ready yet and useless, over-tech things, I think.
Even we have no plan about image cache system(or would change plan later), before having a nice plan, I think we should let user use image module with common HTTP Specs.
So I remove custom ```NSURLCache```, and make logic like below,
1. try fetch image,
2. on response, get ```Date``` on response's header and make ```cacheKey``` with ```Date```.
> (why? because if ```NSURLRequest```'s response was cached, the response's ```Date``` header dosen't change.)
3. find decoded imag
Closes https://github.com/facebook/react-native/pull/8235
Reviewed By: bnham
Differential Revision: D3469086
Pulled By: javache
fbshipit-source-id: 35a5552cda6e6c367481020bbf3c28eb4a9d0207
2016-07-21 14:45:55 +00:00
|
|
|
*
|
|
|
|
* If you provide a custom image decoder, you most implement scheduling yourself,
|
|
|
|
* to avoid decoding large amounts of images at the same time.
|
2015-09-02 15:25:10 +00:00
|
|
|
*/
|
2015-10-19 16:04:54 +00:00
|
|
|
- (RCTImageLoaderCancellationBlock)decodeImageData:(NSData *)imageData
|
|
|
|
size:(CGSize)size
|
|
|
|
scale:(CGFloat)scale
|
2016-01-20 19:03:22 +00:00
|
|
|
resizeMode:(RCTResizeMode)resizeMode
|
2015-10-19 16:04:54 +00:00
|
|
|
completionHandler:(RCTImageLoaderCompletionBlock)completionHandler;
|
2015-09-02 15:25:10 +00:00
|
|
|
|
|
|
|
@optional
|
|
|
|
|
2015-07-27 15:48:31 +00:00
|
|
|
/**
|
2015-10-19 16:04:54 +00:00
|
|
|
* If more than one RCTImageDataDecoder responds YES to `-canDecodeImageData:`
|
|
|
|
* then `decoderPriority` is used to determine which one to use. The decoder
|
|
|
|
* with the highest priority will be selected. Default priority is zero.
|
|
|
|
* If two or more valid decoders have the same priority, the selection order is
|
2015-09-02 15:25:10 +00:00
|
|
|
* undefined.
|
2015-07-27 15:48:31 +00:00
|
|
|
*/
|
2015-10-19 16:04:54 +00:00
|
|
|
- (float)decoderPriority;
|
2015-07-27 15:48:31 +00:00
|
|
|
|
|
|
|
@end
|