mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-24 12:25:59 +08:00
Unify XCAsset handling logic
Summary: @public This diff unifies the logic for detecting when images refer to XCAsset files into a single function (RCTXCAssetNameForURL) and uses it for both +[RCTConvert UIImage:] and RCTImageLoader. I've also tightened the definition of XCAssets so that it only applies to images inside .car files, not any image inside the main bundle. This avoids using the +[UIImage imageNamed:] when not strictly necessary, which is desirable since that method is not thread-safe, and has undocumented caching behavior that is difficult to reason about. Reviewed By: @javache Differential Revision: D2526400 fb-gh-sync-id: 7199c2a44f1d55ff236d2c38a0a9368739b993d5
This commit is contained in:
committed by
facebook-github-bot-4
parent
c16c3f9814
commit
799168929c
@@ -12,6 +12,7 @@
|
||||
#import <objc/message.h>
|
||||
|
||||
#import "RCTDefines.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
@implementation RCTConvert
|
||||
|
||||
@@ -102,7 +103,10 @@ RCT_CUSTOM_CONVERTER(NSData *, NSData, [json dataUsingEncoding:NSUTF8StringEncod
|
||||
// Assume it's a resource path
|
||||
path = [[NSBundle bundleForClass:[self class]].resourcePath stringByAppendingPathComponent:path];
|
||||
}
|
||||
return [NSURL fileURLWithPath:path];
|
||||
if (!(URL = [NSURL fileURLWithPath:path])) {
|
||||
RCTLogConvertError(json, @"a valid URL");
|
||||
}
|
||||
return URL;
|
||||
}
|
||||
@catch (__unused NSException *e) {
|
||||
RCTLogConvertError(json, @"a valid URL");
|
||||
@@ -417,7 +421,9 @@ RCT_CGSTRUCT_CONVERTER(CGAffineTransform, (@[
|
||||
if ([json isKindOfClass:[NSString class]]) {
|
||||
path = json;
|
||||
} else if ([json isKindOfClass:[NSDictionary class]]) {
|
||||
path = [self NSString:json[@"uri"]];
|
||||
if (!(path = [self NSString:json[@"uri"]])) {
|
||||
return nil;
|
||||
}
|
||||
scale = [self CGFloat:json[@"scale"]];
|
||||
isPackagerAsset = [self BOOL:json[@"__packager_asset"]];
|
||||
} else {
|
||||
@@ -427,36 +433,21 @@ RCT_CGSTRUCT_CONVERTER(CGAffineTransform, (@[
|
||||
|
||||
NSURL *URL = [self NSURL:path];
|
||||
NSString *scheme = URL.scheme.lowercaseString;
|
||||
if (URL && [scheme isEqualToString:@"file"]) {
|
||||
if ([URL.path hasPrefix:[NSBundle mainBundle].resourcePath]) {
|
||||
RCTAssertMainThread();
|
||||
|
||||
if ([scheme isEqualToString:@"file"]) {
|
||||
if (RCTIsXCAssetURL(URL)) {
|
||||
// Image may reside inside a .car file, in which case we have no choice
|
||||
// but to use +[UIImage imageNamed] - but this method isn't thread safe
|
||||
static NSMutableDictionary *XCAssetMap = nil;
|
||||
if (!XCAssetMap) {
|
||||
XCAssetMap = [NSMutableDictionary new];
|
||||
}
|
||||
NSNumber *isAsset = XCAssetMap[path];
|
||||
if (!isAsset || isAsset.boolValue) {
|
||||
image = [UIImage imageNamed:path];
|
||||
}
|
||||
if (!isAsset) {
|
||||
// Avoid calling `+imageNamed` again in future if it's not needed.
|
||||
XCAssetMap[path] = @(image != nil);
|
||||
}
|
||||
}
|
||||
|
||||
if (!image) {
|
||||
NSString *filePath = URL.path;
|
||||
|
||||
RCTAssertMainThread();
|
||||
NSString *assetName = RCTBundlePathForURL(URL);
|
||||
image = [UIImage imageNamed:assetName];
|
||||
} else {
|
||||
// Attempt to load from the file system
|
||||
NSString *filePath = URL.path;
|
||||
if (filePath.pathExtension.length == 0) {
|
||||
filePath = [filePath stringByAppendingPathExtension:@"png"];
|
||||
}
|
||||
image = [UIImage imageWithContentsOfFile:filePath];
|
||||
}
|
||||
|
||||
} else if ([scheme isEqualToString:@"data"]) {
|
||||
image = [UIImage imageWithData:[NSData dataWithContentsOfURL:URL]];
|
||||
} else if ([scheme isEqualToString:@"http"] && isPackagerAsset) {
|
||||
|
||||
@@ -77,3 +77,10 @@ RCT_EXTERN NSURL *RCTDataURL(NSString *mimeType, NSData *data);
|
||||
|
||||
// Gzip functionality - compression level in range 0 - 1 (-1 for default)
|
||||
RCT_EXTERN NSData *RCTGzipData(NSData *data, float level);
|
||||
|
||||
// Returns the relative path within the main bundle for an absolute URL
|
||||
// (or nil, if the URL does not specify a path within the main bundle)
|
||||
RCT_EXTERN NSString *RCTBundlePathForURL(NSURL *URL);
|
||||
|
||||
// Determines if a given image URL actually refers to an XCAsset
|
||||
RCT_EXTERN BOOL RCTIsXCAssetURL(NSURL *imageURL);
|
||||
|
||||
@@ -458,3 +458,38 @@ NSData *RCTGzipData(NSData *input, float level)
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
NSString *RCTBundlePathForURL(NSURL *URL)
|
||||
{
|
||||
if (!URL.fileURL) {
|
||||
// Not a file path
|
||||
return nil;
|
||||
}
|
||||
NSString *path = URL.path;
|
||||
NSString *bundlePath = [[NSBundle mainBundle] resourcePath];
|
||||
if (![path hasPrefix:bundlePath]) {
|
||||
// Not a bundle-relative file
|
||||
return nil;
|
||||
}
|
||||
return [path substringFromIndex:bundlePath.length + 1];
|
||||
}
|
||||
|
||||
BOOL RCTIsXCAssetURL(NSURL *imageURL)
|
||||
{
|
||||
NSString *name = RCTBundlePathForURL(imageURL);
|
||||
if (name.pathComponents.count != 1) {
|
||||
// URL is invalid, or is a file path, not an XCAsset identifier
|
||||
return NO;
|
||||
}
|
||||
NSString *extension = [name pathExtension];
|
||||
if (extension.length && ![extension isEqualToString:@"png"]) {
|
||||
// Not a png
|
||||
return NO;
|
||||
}
|
||||
extension = extension.length ? nil : @"png";
|
||||
if ([[NSBundle mainBundle] pathForResource:name ofType:extension]) {
|
||||
// File actually exists in bundle, so is not an XCAsset
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user