Implement Image.queryCache on iOS (#18782)

Summary:
The API was available only on Android (with no mention to that effect in the docs, AFAICT).
This commit adds a simple iOS implementation based on NSURLCache. It should be possible to
query the decoded image cache as well to provide higher fidelity (i.e. "disk", "memory",
"decoded") if the caller passes size, scale, etc. in addition to the image URL, but it's
probably not worth the complexity. The assumption is that callers are interested in the
durability rather than performance aspect of the returned information.

Tested with RNTester on iPhone emulator.

[IOS] [ENHANCEMENT] [Image] - Implemented queryCache
Pull Request resolved: https://github.com/facebook/react-native/pull/18782

Differential Revision: D9411533

Pulled By: hramos

fbshipit-source-id: b430263959bb5f9b8ed9e28bb0a95f8879df881a
This commit is contained in:
EUROPE\laprosek 2018-08-20 16:06:18 -07:00 committed by Facebook Github Bot
parent d846696f49
commit 1658a4c080
5 changed files with 58 additions and 0 deletions

View File

@ -45,11 +45,16 @@ function prefetch(url: string) {
return ImageViewManager.prefetchImage(url);
}
async function queryCache(urls: Array<string>): Promise<Map<string, 'memory' | 'disk'>> {
return await ImageViewManager.queryCache(urls);
}
declare class ImageComponentType extends ReactNative.NativeComponent<
ImagePropsType,
> {
static getSize: typeof getSize;
static prefetch: typeof prefetch;
static queryCache: typeof queryCache;
static resolveAssetSource: typeof resolveAssetSource;
static propTypes: typeof ImageProps;
}
@ -133,6 +138,13 @@ Image.getSize = getSize;
*/
Image.prefetch = prefetch;
/**
* Performs cache interrogation.
*
* See https://facebook.github.io/react-native/docs/image.html#querycache
*/
Image.queryCache = queryCache;
/**
* Resolves an asset reference into an object.
*

View File

@ -129,6 +129,14 @@ typedef dispatch_block_t RCTImageLoaderCancellationBlock;
*/
- (RCTImageLoaderCancellationBlock)getImageSizeForURLRequest:(NSURLRequest *)imageURLRequest
block:(void(^)(NSError *error, CGSize size))completionBlock;
/**
* Determines whether given image URLs are cached locally. The `requests` array is expected
* to contain objects convertible to NSURLRequest. The return value maps URLs to strings:
* "disk" for images known to be cached in non-volatile storage, "memory" for images known
* to be cached in memory. Dictionary items corresponding to images that are not known to be
* cached are simply missing.
*/
- (NSDictionary *)getImageCacheStatus:(NSArray *)requests;
/**
* Allows developers to set their own caching implementation for

View File

@ -779,6 +779,25 @@ static UIImage *RCTResizeImageIfNeeded(UIImage *image,
completionBlock:completion];
}
- (NSDictionary *)getImageCacheStatus:(NSArray *)requests
{
NSMutableDictionary *results = [NSMutableDictionary dictionary];
for (id request in requests) {
NSURLRequest *urlRequest = [RCTConvert NSURLRequest:request];
if (urlRequest) {
NSCachedURLResponse *cachedResponse = [NSURLCache.sharedURLCache cachedResponseForRequest:urlRequest];
if (cachedResponse) {
if (cachedResponse.storagePolicy == NSURLCacheStorageAllowedInMemoryOnly) {
[results setObject:@"memory" forKey:urlRequest.URL.absoluteString];
} else {
[results setObject:@"disk" forKey:urlRequest.URL.absoluteString];
}
}
}
}
return results;
}
#pragma mark - RCTURLRequestHandler
- (BOOL)canHandleRequest:(NSURLRequest *)request

View File

@ -82,4 +82,11 @@ RCT_EXPORT_METHOD(prefetchImage:(NSURLRequest *)request
}];
}
RCT_EXPORT_METHOD(queryCache:(NSArray *)requests
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)
{
resolve([self.bridge.imageLoader getImageCacheStatus:requests]);
}
@end

View File

@ -77,6 +77,18 @@ var NetworkImageCallbackExample = createReactClass({
this._loadEventFired(
`✔ Prefetch OK (+${new Date() - mountTime}ms)`,
);
Image.queryCache([IMAGE_PREFETCH_URL]).then((map) => {
var result = map.get(IMAGE_PREFETCH_URL);
if (result) {
this._loadEventFired(
`✔ queryCache "${result}" (+${new Date() - mountTime}ms)`,
);
} else {
this._loadEventFired(
`✘ queryCache (+${new Date() - mountTime}ms)`,
);
}
});
},
error => {
this._loadEventFired(