mirror of
https://github.com/Tencent/Hippy.git
synced 2026-10-26 03:00:18 +08:00
refactor(ios): image component refactor (#1591)
* feat(ios): add hippy image data loader * feat(ios): add hippy image data loader protocol * feat(ios): add data request for path * refactor(ios): refactor image component data loader
This commit is contained in:
@@ -123,7 +123,6 @@
|
||||
0691853226281E05005D599D /* CALayer+HippyAnimation.m in Sources */ = {isa = PBXBuildFile; fileRef = 0691853126281E05005D599D /* CALayer+HippyAnimation.m */; };
|
||||
06F2A76F2519E319000AF839 /* HippyJSEnginesMapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 06F2A76E2519E319000AF839 /* HippyJSEnginesMapper.mm */; };
|
||||
06F3E3E025A5D867007934F6 /* HippyListTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 06F3E3DF25A5D867007934F6 /* HippyListTableView.m */; };
|
||||
06FF8BD62511BC0400C03900 /* HippyImageProviderProtocol.m in Sources */ = {isa = PBXBuildFile; fileRef = 06FF8BD52511BC0400C03900 /* HippyImageProviderProtocol.m */; };
|
||||
06FF8EEC2511C10B00C03900 /* HippyDefaultImageProvider.m in Sources */ = {isa = PBXBuildFile; fileRef = 06FF8EEB2511C10B00C03900 /* HippyDefaultImageProvider.m */; };
|
||||
06FF8EEF2511C20900C03900 /* NSData+DataType.m in Sources */ = {isa = PBXBuildFile; fileRef = 06FF8EEE2511C20900C03900 /* NSData+DataType.m */; };
|
||||
781580042795449A006E92D4 /* HippyDevInfo.m in Sources */ = {isa = PBXBuildFile; fileRef = 7815800327954499006E92D4 /* HippyDevInfo.m */; };
|
||||
@@ -206,6 +205,7 @@
|
||||
F48291AA274E5BB600D91128 /* HippyOCTurboModule.mm in Sources */ = {isa = PBXBuildFile; fileRef = F48291A7274E5BB500D91128 /* HippyOCTurboModule.mm */; };
|
||||
F48291AB274E5BB600D91128 /* HippyTurboModuleManager.mm in Sources */ = {isa = PBXBuildFile; fileRef = F48291A8274E5BB500D91128 /* HippyTurboModuleManager.mm */; };
|
||||
F48291AC274E5BB600D91128 /* NSObject+HippyTurbo.mm in Sources */ = {isa = PBXBuildFile; fileRef = F48291A9274E5BB500D91128 /* NSObject+HippyTurbo.mm */; };
|
||||
F4833E6727CF24320054A33D /* HippyImageDataLoader.m in Sources */ = {isa = PBXBuildFile; fileRef = F4833E6627CF24320054A33D /* HippyImageDataLoader.m */; };
|
||||
F4AFCB1627BE29D50058AAB1 /* UIView+HippyEvent.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4AFCB1527BE29D50058AAB1 /* UIView+HippyEvent.mm */; };
|
||||
F4CB9D29279270D3008D6F2C /* UIView+RootViewRegister.mm in Sources */ = {isa = PBXBuildFile; fileRef = F4CB9D28279270D3008D6F2C /* UIView+RootViewRegister.mm */; };
|
||||
F4D0028F2675C7D5004A43B6 /* HippyGradientObject.m in Sources */ = {isa = PBXBuildFile; fileRef = F4D0028E2675C7D5004A43B6 /* HippyGradientObject.m */; };
|
||||
@@ -475,7 +475,6 @@
|
||||
06F3E3DE25A5D867007934F6 /* HippyListTableView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HippyListTableView.h; sourceTree = "<group>"; };
|
||||
06F3E3DF25A5D867007934F6 /* HippyListTableView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HippyListTableView.m; sourceTree = "<group>"; };
|
||||
06FF8BD42511BC0400C03900 /* HippyImageProviderProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HippyImageProviderProtocol.h; sourceTree = "<group>"; };
|
||||
06FF8BD52511BC0400C03900 /* HippyImageProviderProtocol.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HippyImageProviderProtocol.m; sourceTree = "<group>"; };
|
||||
06FF8EEA2511C10B00C03900 /* HippyDefaultImageProvider.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HippyDefaultImageProvider.h; sourceTree = "<group>"; };
|
||||
06FF8EEB2511C10B00C03900 /* HippyDefaultImageProvider.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HippyDefaultImageProvider.m; sourceTree = "<group>"; };
|
||||
06FF8EED2511C20900C03900 /* NSData+DataType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSData+DataType.h"; sourceTree = "<group>"; };
|
||||
@@ -654,6 +653,9 @@
|
||||
F48291A7274E5BB500D91128 /* HippyOCTurboModule.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HippyOCTurboModule.mm; sourceTree = "<group>"; };
|
||||
F48291A8274E5BB500D91128 /* HippyTurboModuleManager.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = HippyTurboModuleManager.mm; sourceTree = "<group>"; };
|
||||
F48291A9274E5BB500D91128 /* NSObject+HippyTurbo.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSObject+HippyTurbo.mm"; sourceTree = "<group>"; };
|
||||
F4833E6527CF24320054A33D /* HippyImageDataLoader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HippyImageDataLoader.h; sourceTree = "<group>"; };
|
||||
F4833E6627CF24320054A33D /* HippyImageDataLoader.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = HippyImageDataLoader.m; sourceTree = "<group>"; };
|
||||
F4833E6827CF462C0054A33D /* HippyImageDataLoaderProtocol.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = HippyImageDataLoaderProtocol.h; sourceTree = "<group>"; };
|
||||
F4AFCB1427BE29D50058AAB1 /* UIView+HippyEvent.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+HippyEvent.h"; sourceTree = "<group>"; };
|
||||
F4AFCB1527BE29D50058AAB1 /* UIView+HippyEvent.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "UIView+HippyEvent.mm"; sourceTree = "<group>"; };
|
||||
F4CB9D27279270D3008D6F2C /* UIView+RootViewRegister.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "UIView+RootViewRegister.h"; sourceTree = "<group>"; };
|
||||
@@ -1009,9 +1011,11 @@
|
||||
064C594323AB1A51001E80DD /* HippyAnimatedImageView.h */,
|
||||
064C594723AB1A51001E80DD /* HippyAnimatedImageView.m */,
|
||||
06FF8BD42511BC0400C03900 /* HippyImageProviderProtocol.h */,
|
||||
06FF8BD52511BC0400C03900 /* HippyImageProviderProtocol.m */,
|
||||
06FF8EEA2511C10B00C03900 /* HippyDefaultImageProvider.h */,
|
||||
06FF8EEB2511C10B00C03900 /* HippyDefaultImageProvider.m */,
|
||||
F4833E6527CF24320054A33D /* HippyImageDataLoader.h */,
|
||||
F4833E6627CF24320054A33D /* HippyImageDataLoader.m */,
|
||||
F4833E6827CF462C0054A33D /* HippyImageDataLoaderProtocol.h */,
|
||||
);
|
||||
path = image;
|
||||
sourceTree = "<group>";
|
||||
@@ -1909,7 +1913,6 @@
|
||||
781580042795449A006E92D4 /* HippyDevInfo.m in Sources */,
|
||||
064C5A4A23AB1A51001E80DD /* HippyModuleMethod.mm in Sources */,
|
||||
D84AB9C6273A618B00987D03 /* thread.cc in Sources */,
|
||||
06FF8BD62511BC0400C03900 /* HippyImageProviderProtocol.m in Sources */,
|
||||
F4E7B43E276C61EB00F17139 /* dom_event.cc in Sources */,
|
||||
D84AB9BF273A618B00987D03 /* timer_module.cc in Sources */,
|
||||
D84AB9C5273A618B00987D03 /* task.cc in Sources */,
|
||||
@@ -1924,6 +1927,7 @@
|
||||
064C59F223AB1A51001E80DD /* HippyNetWork.m in Sources */,
|
||||
064C5A0523AB1A51001E80DD /* HippyClipboardModule.m in Sources */,
|
||||
F45D1BDD26B1555E004010EE /* HippyI18nUtils.m in Sources */,
|
||||
F4833E6727CF24320054A33D /* HippyImageDataLoader.m in Sources */,
|
||||
787C199E2726A1020062EBFF /* HippyDomModel.mm in Sources */,
|
||||
7882DFDC272929D300C12149 /* HippyCSSPropsDefine.m in Sources */,
|
||||
064C5A2A23AB1A51001E80DD /* HippyBackgroundImageCacheManager.m in Sources */,
|
||||
|
||||
@@ -783,7 +783,9 @@ HIPPY_NOT_IMPLEMENTED(-(instancetype)initWithBundleURL
|
||||
if (!_valid) {
|
||||
return;
|
||||
}
|
||||
_domManager->TerminateTaskRunner();
|
||||
if (_domManager) {
|
||||
_domManager->TerminateTaskRunner();
|
||||
}
|
||||
HippyAssertMainQueue();
|
||||
HippyAssert(_javaScriptExecutor != nil, @"Can't complete invalidation without a JS executor");
|
||||
|
||||
|
||||
@@ -35,6 +35,8 @@
|
||||
|
||||
@implementation HippyDefaultImageProvider
|
||||
|
||||
@synthesize imageDataPath;
|
||||
|
||||
HIPPY_EXPORT_MODULE(defaultImageProvider)
|
||||
|
||||
+ (BOOL)canHandleData:(NSData *)data {
|
||||
@@ -46,26 +48,22 @@ HIPPY_EXPORT_MODULE(defaultImageProvider)
|
||||
return ret;
|
||||
}
|
||||
|
||||
+ (NSUInteger)priorityForData:(NSData *)data {
|
||||
return 0;
|
||||
}
|
||||
|
||||
+ (instancetype)imageProviderInstanceForData:(NSData *)data {
|
||||
return [[[self class] alloc] initWithData:data];
|
||||
}
|
||||
|
||||
- (instancetype)initWithData:(NSData *)data {
|
||||
self = [super init];
|
||||
if (self) {
|
||||
if ([[self class] isAnimatedImage:data]) {
|
||||
_imageSourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)data, NULL);
|
||||
} else {
|
||||
_data = data;
|
||||
}
|
||||
[self setImageData:data];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)setImageData:(NSData *)imageData {
|
||||
if ([[self class] isAnimatedImage:imageData]) {
|
||||
_imageSourceRef = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
|
||||
} else {
|
||||
_data = imageData;
|
||||
}
|
||||
}
|
||||
|
||||
- (UIImage *)image {
|
||||
if (nil == _image) {
|
||||
if (_data) {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
/*!
|
||||
* iOS SDK
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* Hippy available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "HippyImageDataLoaderProtocol.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
extern NSString *const HippyImageDataLoaderErrorDomain;
|
||||
extern const NSUInteger HippyImageDataLoaderErrorFileNotExists;
|
||||
extern const NSUInteger HippyImageDataLoaderErrorNoPathIncoming;
|
||||
extern const NSUInteger HippyImageDataLoaderErrorPathToUrl;
|
||||
|
||||
@interface HippyImageDataLoader : NSObject<HippyImageDataLoaderProtocol>
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -0,0 +1,231 @@
|
||||
/*!
|
||||
* iOS SDK
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* Hippy available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "HippyImageDataLoader.h"
|
||||
#import "HippyUtils.h"
|
||||
#import "HippyImageCacheManager.h"
|
||||
|
||||
NSString *const HippyImageDataLoaderErrorDomain = @"HippyImageDataLoaderErrorDomain";
|
||||
|
||||
const NSUInteger HippyImageDataLoaderErrorFileNotExists = 1000;
|
||||
const NSUInteger HippyImageDataLoaderErrorNoPathIncoming = 1001;
|
||||
const NSUInteger HippyImageDataLoaderErrorPathToUrl = 1002;
|
||||
|
||||
typedef NS_ENUM(NSUInteger, ImagePathType) {
|
||||
ImagePathTypeUnknown,
|
||||
ImagePathTypeHTTPPath,
|
||||
ImagePathTypeFilePath,
|
||||
ImagePathTypeBase64Path,
|
||||
};
|
||||
|
||||
typedef void(^DownloadProgress)(NSUInteger, NSUInteger);
|
||||
typedef void(^CompletionBlock)(id, NSString *, NSError *);
|
||||
|
||||
static ImagePathType checkPathTypeFromPath(NSString *path) {
|
||||
ImagePathType type = ImagePathTypeUnknown;
|
||||
if ([path hasPrefix:@"http"]) {
|
||||
type = ImagePathTypeHTTPPath;
|
||||
}
|
||||
else if ([path hasPrefix:@"file://"]) {
|
||||
type = ImagePathTypeFilePath;
|
||||
}
|
||||
else if ([path containsString:@"data:image/"] && [path containsString:@";base64,"]) {
|
||||
type = ImagePathTypeBase64Path;
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
static NSOperationQueue *ImageDataLoaderQueue(void) {
|
||||
static dispatch_once_t onceToken;
|
||||
static NSOperationQueue *_hippy_image_queue = nil;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_hippy_image_queue = [[NSOperationQueue alloc] init];
|
||||
_hippy_image_queue.maxConcurrentOperationCount = 1;
|
||||
});
|
||||
return _hippy_image_queue;
|
||||
}
|
||||
|
||||
@interface HippyImageDataLoader ()<NSURLSessionDataDelegate> {
|
||||
ImagePathType _imagePathType;
|
||||
NSURLSessionDataTask *_task;
|
||||
NSMutableData *_imageData;
|
||||
NSUInteger _imageDataTotalLength;
|
||||
DownloadProgress _progress;
|
||||
CompletionBlock _completion;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation HippyImageDataLoader
|
||||
|
||||
#pragma mark HippyImageDataLoaderProtocol Implementation
|
||||
|
||||
- (BOOL)canHandleImageAtPath:(NSString *)path {
|
||||
ImagePathType type = checkPathTypeFromPath(path);
|
||||
return ImagePathTypeUnknown != type;
|
||||
}
|
||||
|
||||
- (void)loadImageAtPath:(NSString *)path progress:(DownloadProgress)progress
|
||||
completion:(CompletionBlock)dataCompletion {
|
||||
ImagePathType type = checkPathTypeFromPath(path);
|
||||
switch (type) {
|
||||
case ImagePathTypeHTTPPath:
|
||||
[self loadImageAtHTTPPath:path progress:progress dataCompletion:dataCompletion];
|
||||
break;
|
||||
case ImagePathTypeFilePath:
|
||||
[self loadImageAtFilePath:path progress:progress dataCompletion:dataCompletion];
|
||||
break;
|
||||
case ImagePathTypeBase64Path:
|
||||
[self loadImageAtBase64Path:path progress:progress dataCompletion:dataCompletion];
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancelImageDownloadAtPath:(NSString *)path {
|
||||
[_task cancel];
|
||||
}
|
||||
|
||||
#pragma mark Image Data Loader
|
||||
|
||||
- (void)loadImageAtHTTPPath:(NSString *)path progress:(DownloadProgress)progress dataCompletion:(CompletionBlock)dataCompletion {
|
||||
if (_task) {
|
||||
[_task cancel];
|
||||
}
|
||||
NSURL *sourceUrl = HippyURLWithString(path, nil);
|
||||
if (sourceUrl) {
|
||||
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
|
||||
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self
|
||||
delegateQueue:ImageDataLoaderQueue()];
|
||||
_task = [session dataTaskWithURL:sourceUrl];
|
||||
[_task resume];
|
||||
_progress = progress;
|
||||
_completion = dataCompletion;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadImageAtFilePath:(NSString *)path progress:(DownloadProgress)progress dataCompletion:(CompletionBlock)dataCompletion {
|
||||
if (path) {
|
||||
BOOL isDirectory = NO;
|
||||
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDirectory];
|
||||
if (fileExists) {
|
||||
NSError *error = nil;
|
||||
NSData *data = [NSData dataWithContentsOfFile:path options:NSDataReadingMappedIfSafe error:&error];
|
||||
if (error) {
|
||||
dataCompletion(nil, path, error);
|
||||
}
|
||||
else {
|
||||
NSUInteger length = [data length];
|
||||
if (progress) {
|
||||
progress(length, length);
|
||||
}
|
||||
if (dataCompletion) {
|
||||
dataCompletion(data, path, nil);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
if (dataCompletion) {
|
||||
NSError *error = [NSError errorWithDomain:HippyImageDataLoaderErrorDomain code:HippyImageDataLoaderErrorFileNotExists userInfo:@{@"path": path}];
|
||||
dataCompletion(nil, path, error);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
if (dataCompletion) {
|
||||
NSError *error = [NSError errorWithDomain:HippyImageDataLoaderErrorDomain code:HippyImageDataLoaderErrorNoPathIncoming userInfo:nil];
|
||||
dataCompletion(nil, path, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)loadImageAtBase64Path:(NSString *)path progress:(DownloadProgress)progress dataCompletion:(CompletionBlock)dataCompletion {
|
||||
if (path) {
|
||||
NSURL *url = [NSURL URLWithString:path];
|
||||
if (url) {
|
||||
NSError *error = nil;
|
||||
NSData *data = [NSData dataWithContentsOfURL:url options:NSDataReadingMappedIfSafe error:&error];
|
||||
if (error) {
|
||||
dataCompletion(nil, path, error);
|
||||
}else {
|
||||
NSUInteger length = [data length];
|
||||
if (progress) {
|
||||
progress(length, length);
|
||||
}
|
||||
if (dataCompletion) {
|
||||
dataCompletion(data, path, nil);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
if (dataCompletion) {
|
||||
NSError *error = [NSError errorWithDomain:HippyImageDataLoaderErrorDomain code:HippyImageDataLoaderErrorNoPathIncoming userInfo:nil];
|
||||
dataCompletion(nil, path, error);
|
||||
}
|
||||
}
|
||||
}else {
|
||||
if (dataCompletion) {
|
||||
NSError *error = [NSError errorWithDomain:HippyImageDataLoaderErrorDomain code:HippyImageDataLoaderErrorNoPathIncoming userInfo:nil];
|
||||
dataCompletion(nil, path, error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark URL request delegate implementation
|
||||
- (void)URLSession:(__unused NSURLSession *)session
|
||||
dataTask:(NSURLSessionDataTask *)dataTask
|
||||
didReceiveResponse:(NSURLResponse *)response
|
||||
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
|
||||
if (_task == dataTask) {
|
||||
_imageDataTotalLength = response.expectedContentLength;
|
||||
completionHandler(NSURLSessionResponseAllow);
|
||||
NSUInteger capacity =
|
||||
NSURLResponseUnknownLength != _imageDataTotalLength ? (NSUInteger)_imageDataTotalLength : 256;
|
||||
_imageData = [[NSMutableData alloc] initWithCapacity:capacity];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(__unused NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask
|
||||
didReceiveData:(NSData *)data {
|
||||
if (_task == dataTask) {
|
||||
[_imageData appendData:data];
|
||||
if (_progress) {
|
||||
_progress([_imageData length], _imageDataTotalLength);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(__unused NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error {
|
||||
if (_task == task) {
|
||||
if (_progress) {
|
||||
_progress([_imageData length], _imageDataTotalLength);
|
||||
}
|
||||
if (_completion) {
|
||||
_completion(_imageData, [[[task originalRequest] URL] absoluteString], error);
|
||||
}
|
||||
}
|
||||
[session finishTasksAndInvalidate];
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[_task cancel];
|
||||
}
|
||||
|
||||
@end
|
||||
@@ -0,0 +1,43 @@
|
||||
/*!
|
||||
* iOS SDK
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* Hippy available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@protocol HippyImageDataLoaderProtocol <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
- (BOOL)canHandleImageAtPath:(NSString *)path;
|
||||
|
||||
@required
|
||||
|
||||
- (void)loadImageAtPath:(NSString *)path progress:(void (^)(NSUInteger, NSUInteger))progress
|
||||
completion:(void (^)(id, NSString *, NSError *))completion;
|
||||
|
||||
- (void)cancelImageDownloadAtPath:(NSString *)path;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
@@ -37,14 +37,14 @@
|
||||
*/
|
||||
+ (BOOL)isAnimatedImage:(NSData *)data;
|
||||
|
||||
/** return priority for data
|
||||
* instance with higher priority will process data
|
||||
*/
|
||||
+ (NSUInteger)priorityForData:(NSData *)data;
|
||||
@property(nonatomic, copy)NSString *imageDataPath;
|
||||
|
||||
/** return image provider instance for data
|
||||
/**
|
||||
* Set image data for provider
|
||||
*
|
||||
* @param data Image data
|
||||
*/
|
||||
+ (instancetype)imageProviderInstanceForData:(NSData *)data;
|
||||
- (void)setImageData:(NSData *)data;
|
||||
|
||||
/** return image.If it is an animated image,return first frame
|
||||
*/
|
||||
|
||||
@@ -1,51 +0,0 @@
|
||||
/*!
|
||||
* iOS SDK
|
||||
*
|
||||
* Tencent is pleased to support the open source community by making
|
||||
* Hippy available.
|
||||
*
|
||||
* Copyright (C) 2019 THL A29 Limited, a Tencent company.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#import "HippyImageProviderProtocol.h"
|
||||
#import "objc/runtime.h"
|
||||
#import "HippyBridge.h"
|
||||
|
||||
Class<HippyImageProviderProtocol> imageProviderClassFromBridge(NSData *data, HippyBridge *bridge) {
|
||||
NSSet<Class<HippyImageProviderProtocol>> *classes = [bridge imageProviders];
|
||||
NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id _Nullable evaluatedObject, NSDictionary<NSString *, id> *_Nullable bindings) {
|
||||
if ([evaluatedObject conformsToProtocol:@protocol(HippyImageProviderProtocol)]) {
|
||||
Class<HippyImageProviderProtocol> class = (Class<HippyImageProviderProtocol>)evaluatedObject;
|
||||
return [class canHandleData:data];
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
}];
|
||||
NSSet<Class<HippyImageProviderProtocol>> *sub = [classes filteredSetUsingPredicate:predicate];
|
||||
Class<HippyImageProviderProtocol> candidate = nil;
|
||||
for (Class<HippyImageProviderProtocol> class in sub) {
|
||||
if (nil == candidate) {
|
||||
candidate = class;
|
||||
} else {
|
||||
NSUInteger candidatePriority = [candidate priorityForData:data];
|
||||
NSUInteger classPriority = [class priorityForData:data];
|
||||
if (classPriority > candidatePriority) {
|
||||
candidate = class;
|
||||
}
|
||||
}
|
||||
}
|
||||
return candidate;
|
||||
}
|
||||
@@ -78,7 +78,7 @@ typedef NS_ENUM(NSInteger, HippyResizeMode) {
|
||||
|
||||
- (void)updateImage:(UIImage *)image;
|
||||
|
||||
- (UIImage *)imageFromData:(NSData *)data;
|
||||
- (void)setImageProvider:(id<HippyImageProviderProtocol>)imageProvider;
|
||||
|
||||
- (void)clearImageIfDetached;
|
||||
|
||||
|
||||
@@ -25,7 +25,6 @@
|
||||
#import "HippyUtils.h"
|
||||
#import "HippyImageViewCustomLoader.h"
|
||||
#import "HippyBridge+LocalFileSource.h"
|
||||
#import "HippyImageCacheManager.h"
|
||||
#import "HippyAnimatedImage.h"
|
||||
#import "HippyDefaultImageProvider.h"
|
||||
#import <Accelerate/Accelerate.h>
|
||||
@@ -46,16 +45,6 @@ typedef struct _BorderRadiusStruct {
|
||||
CGFloat bottomRightRadius;
|
||||
} BorderRadiusStruct;
|
||||
|
||||
static NSOperationQueue *hippy_image_queue() {
|
||||
static dispatch_once_t onceToken;
|
||||
static NSOperationQueue *_hippy_image_queue = nil;
|
||||
dispatch_once(&onceToken, ^{
|
||||
_hippy_image_queue = [[NSOperationQueue alloc] init];
|
||||
_hippy_image_queue.maxConcurrentOperationCount = 1;
|
||||
});
|
||||
return _hippy_image_queue;
|
||||
}
|
||||
|
||||
static NSOperationQueue *animated_image_queue() {
|
||||
static dispatch_once_t onceToken;
|
||||
static NSOperationQueue *_animatedImageOQ = nil;
|
||||
@@ -197,15 +186,12 @@ NSError *imageErrorFromParams(NSInteger errorCode, NSString *errorDescription) {
|
||||
@end
|
||||
|
||||
@interface HippyImageView () {
|
||||
NSURLSessionDataTask *_task;
|
||||
NSURL *_imageLoadURL;
|
||||
long long _totalLength;
|
||||
NSMutableData *_data;
|
||||
__weak CALayer *_borderWidthLayer;
|
||||
BOOL _needsUpdateBorderRadius;
|
||||
CGSize _size;
|
||||
BOOL _needsReloadImage;
|
||||
BOOL _needsUpdateImage;
|
||||
id<HippyImageProviderProtocol> _imageProvider;
|
||||
}
|
||||
|
||||
@property (nonatomic) HippyAnimatedImageOperation *animatedImageOperation;
|
||||
@@ -236,7 +222,6 @@ NSError *imageErrorFromParams(NSInteger errorCode, NSString *errorDescription) {
|
||||
- (void)didMoveToWindow {
|
||||
[super didMoveToWindow];
|
||||
if (!self.window) {
|
||||
[self cancelImageLoad];
|
||||
} else if ([self shouldChangeImageSource]) {
|
||||
[self reloadImage];
|
||||
}
|
||||
@@ -309,7 +294,6 @@ NSError *imageErrorFromParams(NSInteger errorCode, NSString *errorDescription) {
|
||||
- (void)setResizeMode:(HippyResizeMode)resizeMode {
|
||||
if (_resizeMode != resizeMode) {
|
||||
_resizeMode = resizeMode;
|
||||
|
||||
if (_resizeMode == HippyResizeModeRepeat) {
|
||||
self.contentMode = UIViewContentModeScaleToFill;
|
||||
} else {
|
||||
@@ -328,6 +312,12 @@ NSError *imageErrorFromParams(NSInteger errorCode, NSString *errorDescription) {
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setImageProvider:(id<HippyImageProviderProtocol>)imageProvider {
|
||||
if (_imageProvider != imageProvider) {
|
||||
_imageProvider = imageProvider;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)didSetProps:(NSArray<NSString *> *)changedProps {
|
||||
if (_needsReloadImage) {
|
||||
self.animatedImage = nil;
|
||||
@@ -354,311 +344,40 @@ NSError *imageErrorFromParams(NSInteger errorCode, NSString *errorDescription) {
|
||||
}
|
||||
|
||||
- (void)reloadImage {
|
||||
NSDictionary *source = [self.source firstObject];
|
||||
if (source && CGRectGetWidth(self.frame) > 0 && CGRectGetHeight(self.frame) > 0) {
|
||||
if (_onLoadStart) {
|
||||
_onLoadStart(@{});
|
||||
}
|
||||
NSString *uri = source[@"uri"];
|
||||
self.pendingImageSourceUri = uri;
|
||||
BOOL isBlurredImage = NO;
|
||||
NSData *data = [[HippyImageCacheManager sharedInstance] imageCacheDataForURLString:uri];
|
||||
if (data) {
|
||||
Class<HippyImageProviderProtocol> ipClass = imageProviderClassFromBridge(data, self.bridge);
|
||||
id<HippyImageProviderProtocol> instance = [ipClass imageProviderInstanceForData:data];
|
||||
if (instance) {
|
||||
BOOL isAnimatedImage = [instance imageCount] > 1;
|
||||
if (isAnimatedImage) {
|
||||
if (_animatedImageOperation) {
|
||||
[_animatedImageOperation cancel];
|
||||
}
|
||||
_animatedImageOperation = [[HippyAnimatedImageOperation alloc] initWithAnimatedImageProvider:instance imageView:self
|
||||
imageURL:uri];
|
||||
[animated_image_queue() addOperation:_animatedImageOperation];
|
||||
} else {
|
||||
UIImage *image = [instance image];
|
||||
if (image) {
|
||||
[self loadImage:image url:uri error:nil needBlur:!isBlurredImage needCache:YES];
|
||||
} else {
|
||||
NSString *errorMessage = [NSString stringWithFormat:@"image data unavailable for uri %@", uri];
|
||||
NSError *theError = imageErrorFromParams(ImageDataUnavailable, errorMessage);
|
||||
[self loadImage:nil url:uri error:theError needBlur:YES needCache:NO];
|
||||
}
|
||||
}
|
||||
return;
|
||||
if (_imageProvider) {
|
||||
NSString *imagePath = _imageProvider.imageDataPath;
|
||||
BOOL isAnimatedImage = [_imageProvider imageCount] > 1;
|
||||
if (isAnimatedImage) {
|
||||
if (_animatedImageOperation) {
|
||||
[_animatedImageOperation cancel];
|
||||
}
|
||||
}
|
||||
|
||||
if ([uri hasPrefix:@"file://"]) {
|
||||
NSURL *fileURL = [NSURL URLWithString:uri];
|
||||
NSError *error = nil;
|
||||
NSData *imageData = [NSData dataWithContentsOfURL:fileURL options:(NSDataReadingMappedIfSafe) error:&error];
|
||||
if (error) {
|
||||
NSString *errorMessage = [NSString stringWithFormat:@"image data unavailable for uri %@", uri];
|
||||
_animatedImageOperation =
|
||||
[[HippyAnimatedImageOperation alloc] initWithAnimatedImageProvider:_imageProvider
|
||||
imageView:self
|
||||
imageURL:imagePath];
|
||||
[animated_image_queue() addOperation:_animatedImageOperation];
|
||||
}else {
|
||||
UIImage *image = [_imageProvider image];
|
||||
if (image) {
|
||||
[self loadImage:image url:imagePath error:nil needBlur:YES];
|
||||
} else {
|
||||
NSString *errorMessage = [NSString stringWithFormat:@"image data unavailable for uri %@", _imageProvider.imageDataPath];
|
||||
NSError *theError = imageErrorFromParams(ImageDataUnavailable, errorMessage);
|
||||
[self loadImage:nil url:uri error:theError needBlur:YES needCache:NO];
|
||||
}
|
||||
else {
|
||||
Class<HippyImageProviderProtocol> ipClass = imageProviderClassFromBridge(imageData, self.bridge);
|
||||
id<HippyImageProviderProtocol> instance = [self instanceImageProviderFromClass:ipClass imageData:imageData];
|
||||
BOOL isAnimatedImage = [ipClass isAnimatedImage:imageData];
|
||||
if (isAnimatedImage) {
|
||||
if (_animatedImageOperation) {
|
||||
[_animatedImageOperation cancel];
|
||||
}
|
||||
_animatedImageOperation = [[HippyAnimatedImageOperation alloc] initWithAnimatedImageProvider:instance imageView:self
|
||||
imageURL:source[@"uri"]];
|
||||
[animated_image_queue() addOperation:_animatedImageOperation];
|
||||
} else {
|
||||
UIImage *image = [instance image];
|
||||
if (image) {
|
||||
[self loadImage:image url:uri error:nil needBlur:YES needCache:YES];
|
||||
} else {
|
||||
NSString *errorMessage = [NSString stringWithFormat:@"image data unavailable for uri %@", uri];
|
||||
NSError *theError = imageErrorFromParams(ImageDataUnavailable, errorMessage);
|
||||
[self loadImage:nil url:uri error:theError needBlur:YES needCache:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
NSData *uriData = [uri dataUsingEncoding:NSUTF8StringEncoding];
|
||||
if (nil == uriData) {
|
||||
return;
|
||||
}
|
||||
CFURLRef urlRef = CFURLCreateWithBytes(NULL, [uriData bytes], [uriData length], kCFStringEncodingUTF8, NULL);
|
||||
NSURL *source_url = CFBridgingRelease(urlRef);
|
||||
if ([HippyBridge isHippyLocalFileURLString:uri]) {
|
||||
NSString *localPath = [_bridge absoluteStringFromHippyLocalFileURLString:uri];
|
||||
BOOL isDirectory = NO;
|
||||
BOOL fileExist = [[NSFileManager defaultManager] fileExistsAtPath:localPath isDirectory:&isDirectory];
|
||||
if (fileExist && !isDirectory) {
|
||||
NSData *imageData = [NSData dataWithContentsOfFile:localPath];
|
||||
Class<HippyImageProviderProtocol> ipClass = imageProviderClassFromBridge(imageData, self.bridge);
|
||||
id<HippyImageProviderProtocol> instance = [self instanceImageProviderFromClass:ipClass imageData:imageData];
|
||||
BOOL isAnimatedImage = [ipClass isAnimatedImage:imageData];
|
||||
if (isAnimatedImage) {
|
||||
if (_animatedImageOperation) {
|
||||
[_animatedImageOperation cancel];
|
||||
}
|
||||
_animatedImageOperation = [[HippyAnimatedImageOperation alloc] initWithAnimatedImageProvider:instance imageView:self
|
||||
imageURL:source[@"uri"]];
|
||||
[animated_image_queue() addOperation:_animatedImageOperation];
|
||||
} else {
|
||||
UIImage *image = [instance image];
|
||||
if (image) {
|
||||
[self loadImage:image url:source_url.absoluteString error:nil needBlur:YES needCache:YES];
|
||||
} else {
|
||||
NSString *errorMessage = [NSString stringWithFormat:@"image data unavailable for uri %@", source_url.absoluteString];
|
||||
NSError *theError = imageErrorFromParams(ImageDataUnavailable, errorMessage);
|
||||
[self loadImage:nil url:source_url.absoluteString error:theError needBlur:YES needCache:NO];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NSString *errorMessage = [NSString stringWithFormat:@"local image data not exist %@", source_url.absoluteString];
|
||||
NSError *error = imageErrorFromParams(ImageDataNotExist, errorMessage);
|
||||
[self loadImage:nil url:source_url.absoluteString error:error needBlur:YES needCache:NO];
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
__weak __typeof(self) weakSelf = self;
|
||||
|
||||
typedef void (^HandleBase64CompletedBlock)(NSString *);
|
||||
HandleBase64CompletedBlock handleBase64CompletedBlock = ^void(NSString *base64Data) {
|
||||
NSRange range = [base64Data rangeOfString:@";base64,"];
|
||||
if (NSNotFound != range.location) {
|
||||
base64Data = [base64Data substringFromIndex:range.location + range.length];
|
||||
NSData *imageData = [[NSData alloc] initWithBase64EncodedString:base64Data options:NSDataBase64DecodingIgnoreUnknownCharacters];
|
||||
Class<HippyImageProviderProtocol> ipClass = imageProviderClassFromBridge(imageData, self.bridge);
|
||||
id<HippyImageProviderProtocol> instance = [self instanceImageProviderFromClass:ipClass imageData:imageData];
|
||||
BOOL isAnimatedImage = [ipClass isAnimatedImage:imageData];
|
||||
if (isAnimatedImage) {
|
||||
if (weakSelf.animatedImageOperation) {
|
||||
[weakSelf.animatedImageOperation cancel];
|
||||
}
|
||||
weakSelf.animatedImageOperation = [[HippyAnimatedImageOperation alloc] initWithAnimatedImageProvider:instance imageView:self
|
||||
imageURL:source[@"uri"]];
|
||||
[animated_image_queue() addOperation:weakSelf.animatedImageOperation];
|
||||
} else {
|
||||
UIImage *image = [instance image];
|
||||
if (image) {
|
||||
[weakSelf loadImage:image url:source[@"uri"] error:nil needBlur:YES needCache:YES];
|
||||
} else {
|
||||
NSError *error = imageErrorFromParams(ImageDataUnavailable, @"base64 data not available");
|
||||
[self loadImage:nil url:source[@"uri"] error:error needBlur:YES needCache:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
typedef void (^HandleImageCompletedBlock)(NSURL *);
|
||||
HandleImageCompletedBlock handleImageCompletedBlock = ^void(NSURL *source_url) {
|
||||
[weakSelf.bridge.imageLoader imageView:weakSelf loadAtUrl:source_url placeholderImage:weakSelf.defaultImage context:NULL
|
||||
progress:^(long long currentLength, long long totalLength) {
|
||||
if (weakSelf.onProgress) {
|
||||
weakSelf.onProgress(@{@"loaded": @((double)currentLength), @"total": @((double)totalLength)});
|
||||
}
|
||||
}
|
||||
completed:^(NSData *data, NSURL *url, NSError *error) {
|
||||
Class<HippyImageProviderProtocol> ipClass = imageProviderClassFromBridge(data, self.bridge);
|
||||
id<HippyImageProviderProtocol> instance = [self instanceImageProviderFromClass:ipClass imageData:data];
|
||||
BOOL isAnimatedImage = [ipClass isAnimatedImage:data];
|
||||
if (isAnimatedImage) {
|
||||
if (weakSelf.animatedImageOperation) {
|
||||
[weakSelf.animatedImageOperation cancel];
|
||||
}
|
||||
weakSelf.animatedImageOperation = [[HippyAnimatedImageOperation alloc] initWithAnimatedImageProvider:instance imageView:self
|
||||
imageURL:source[@"uri"]];
|
||||
[animated_image_queue() addOperation:weakSelf.animatedImageOperation];
|
||||
} else {
|
||||
UIImage *image = [instance image];
|
||||
if (image) {
|
||||
[weakSelf loadImage:image url:source[@"uri"] error:nil needBlur:YES needCache:YES];
|
||||
} else {
|
||||
NSString *errorMessage = [NSString stringWithFormat:@"image data unavailable %@", source[@"uri"]];
|
||||
NSError *error = imageErrorFromParams(ImageDataUnavailable, errorMessage);
|
||||
[weakSelf loadImage:nil url:source[@"uri"] error:error needBlur:YES needCache:NO];
|
||||
}
|
||||
}
|
||||
}];
|
||||
};
|
||||
|
||||
if (_bridge.imageLoader && source_url) {
|
||||
if (_defaultImage) {
|
||||
weakSelf.image = _defaultImage;
|
||||
}
|
||||
|
||||
if ([[source_url absoluteString] hasPrefix:@"data:image/"]) {
|
||||
handleBase64CompletedBlock([source_url absoluteString]);
|
||||
} else {
|
||||
if (_imageLoadURL) {
|
||||
[_bridge.imageLoader cancelImageDownload:self withUrl:_imageLoadURL];
|
||||
}
|
||||
_imageLoadURL = source_url;
|
||||
handleImageCompletedBlock(source_url);
|
||||
}
|
||||
|
||||
} else {
|
||||
if ([uri hasPrefix:@"data:image/"]) {
|
||||
handleBase64CompletedBlock(uri);
|
||||
} else {
|
||||
if (_task) {
|
||||
[self cancelImageLoad];
|
||||
}
|
||||
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
|
||||
NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration delegate:self delegateQueue:hippy_image_queue()];
|
||||
_task = [session dataTaskWithURL:source_url];
|
||||
[_task resume];
|
||||
[self loadImage:nil url:imagePath error:theError needBlur:YES];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cancelImageLoad {
|
||||
self.pendingImageSourceUri = nil;
|
||||
NSDictionary *source = [self.source firstObject];
|
||||
if (_bridge.imageLoader) {
|
||||
[_animatedImageOperation cancel];
|
||||
_animatedImageOperation = nil;
|
||||
[_bridge.imageLoader cancelImageDownload:self withUrl:source[@"uri"]];
|
||||
} else {
|
||||
[_task cancel];
|
||||
_task = nil;
|
||||
[hippy_image_queue() addOperationWithBlock:^{
|
||||
self->_data = nil;
|
||||
self->_totalLength = 0;
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)clearImage {
|
||||
[self cancelImageLoad];
|
||||
[self.layer removeAnimationForKey:@"contents"];
|
||||
self.image = nil;
|
||||
self.imageSourceUri = nil;
|
||||
}
|
||||
|
||||
- (UIImage *)imageFromData:(NSData *)data {
|
||||
if (nil == data) {
|
||||
return nil;
|
||||
}
|
||||
Class<HippyImageProviderProtocol> ipClass = imageProviderClassFromBridge(data, self.bridge);
|
||||
id<HippyImageProviderProtocol> instance = [self instanceImageProviderFromClass:ipClass imageData:data];
|
||||
return [instance image];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
- (void)URLSession:(__unused NSURLSession *)session
|
||||
dataTask:(__unused NSURLSessionDataTask *)dataTask
|
||||
didReceiveResponse:(NSURLResponse *)response
|
||||
completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
|
||||
if (_task == dataTask) {
|
||||
_totalLength = response.expectedContentLength;
|
||||
completionHandler(NSURLSessionResponseAllow);
|
||||
NSUInteger capacity = NSURLResponseUnknownLength != _totalLength ? (NSUInteger)_totalLength : 256;
|
||||
_data = [[NSMutableData alloc] initWithCapacity:capacity];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(__unused NSURLSession *)session dataTask:(__unused NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
|
||||
if (_task == dataTask) {
|
||||
if (_onProgress && NSURLResponseUnknownLength != _totalLength) {
|
||||
_onProgress(@{ @"loaded": @((double)data.length), @"total": @((double)_totalLength) });
|
||||
}
|
||||
[_data appendData:data];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(__unused NSURLSession *)session task:(nonnull NSURLSessionTask *)task didCompleteWithError:(nullable NSError *)error {
|
||||
if (_task == task) {
|
||||
NSString *urlString = [[[task originalRequest] URL] absoluteString];
|
||||
if (!error) {
|
||||
if ([_data length] > 0) {
|
||||
Class<HippyImageProviderProtocol> ipClass = imageProviderClassFromBridge(_data, self.bridge);
|
||||
id<HippyImageProviderProtocol> instance = [self instanceImageProviderFromClass:ipClass imageData:_data];
|
||||
BOOL isAnimatedImage = [ipClass isAnimatedImage:_data];
|
||||
if (isAnimatedImage) {
|
||||
if (_animatedImageOperation) {
|
||||
[_animatedImageOperation cancel];
|
||||
}
|
||||
_animatedImageOperation = [[HippyAnimatedImageOperation alloc] initWithAnimatedImageProvider:instance imageView:self
|
||||
imageURL:urlString];
|
||||
[animated_image_queue() addOperation:_animatedImageOperation];
|
||||
} else {
|
||||
UIImage *image = [self imageFromData:_data];
|
||||
;
|
||||
if (image) {
|
||||
[[HippyImageCacheManager sharedInstance] setImageCacheData:_data forURLString:urlString];
|
||||
[self loadImage:image url:urlString error:nil needBlur:YES needCache:YES];
|
||||
} else {
|
||||
NSString *errorMessage = [NSString stringWithFormat:@"image data unavailable %@", urlString];
|
||||
NSError *theError = imageErrorFromParams(ImageDataUnavailable, errorMessage);
|
||||
[self loadImage:nil url:urlString error:theError needBlur:YES needCache:NO];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NSURLResponse *response = [task response];
|
||||
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
NSUInteger statusCode = [httpResponse statusCode];
|
||||
NSString *errorMessage = [NSString stringWithFormat:@"no data received, HTTPStatusCode is %zd, url is %@", statusCode, urlString];
|
||||
NSError *imgError = imageErrorFromParams(ImageDataUnavailable, errorMessage);
|
||||
[self loadImage:nil url:urlString error:imgError needBlur:NO needCache:NO];
|
||||
}
|
||||
}
|
||||
} else {
|
||||
NSError *imgError = imageErrorFromParams(ImageDataReceivedError, error.localizedDescription);
|
||||
[self loadImage:nil url:urlString error:imgError needBlur:YES needCache:NO];
|
||||
}
|
||||
}
|
||||
[session finishTasksAndInvalidate];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (void)loadImage:(UIImage *)image url:(NSString *)url error:(NSError *)error needBlur:(BOOL)needBlur needCache:(BOOL)needCache {
|
||||
- (void)loadImage:(UIImage *)image url:(NSString *)url error:(NSError *)error needBlur:(BOOL)needBlur {
|
||||
if (error) {
|
||||
if (_onError && error.code != NSURLErrorCancelled) {
|
||||
_onError(@{ @"error": error.localizedDescription, @"errorCode": @(error.code), @"errorURL": url });
|
||||
@@ -668,8 +387,7 @@ NSError *imageErrorFromParams(NSInteger errorCode, NSString *errorDescription) {
|
||||
}
|
||||
return;
|
||||
}
|
||||
NSDictionary *source = [self.source firstObject];
|
||||
NSString *currentImageURLString = [source objectForKey:@"uri"];
|
||||
NSString *currentImageURLString = _imageProvider.imageDataPath;
|
||||
BOOL shouldContinue = url && currentImageURLString && [url isEqualToString:currentImageURLString];
|
||||
if (!shouldContinue) {
|
||||
return;
|
||||
@@ -705,18 +423,12 @@ NSError *imageErrorFromParams(NSInteger errorCode, NSString *errorDescription) {
|
||||
NSError *finalError = HippyErrorFromErrorAndModuleName(error, self.bridge.moduleName);
|
||||
HippyFatal(finalError);
|
||||
}
|
||||
if (needCache) {
|
||||
[[HippyImageCacheManager sharedInstance] setImage:blurredImage forURLString:url blurRadius:br];
|
||||
}
|
||||
HippyExecuteOnMainQueue(^{
|
||||
setImageBlock(blurredImage);
|
||||
});
|
||||
});
|
||||
} else {
|
||||
HippyExecuteOnMainQueue(^{
|
||||
if (needCache) {
|
||||
[[HippyImageCacheManager sharedInstance] setImage:image forURLString:url blurRadius:br];
|
||||
}
|
||||
setImageBlock(image);
|
||||
});
|
||||
}
|
||||
@@ -885,16 +597,6 @@ NSError *imageErrorFromParams(NSInteger errorCode, NSString *errorDescription) {
|
||||
return radius;
|
||||
}
|
||||
|
||||
- (id<HippyImageProviderProtocol>)instanceImageProviderFromClass:(Class<HippyImageProviderProtocol>)cls imageData:(NSData *)data {
|
||||
id<HippyImageProviderProtocol> instance = [cls imageProviderInstanceForData:data];
|
||||
if ([instance isKindOfClass:[HippyDefaultImageProvider class]]) {
|
||||
HippyDefaultImageProvider *provider = (HippyDefaultImageProvider *)instance;
|
||||
provider.imageViewSize = _size;
|
||||
provider.downSample = _downSample;
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation UIImage (Hippy)
|
||||
@@ -958,7 +660,7 @@ HIPPY_ENUM_CONVERTER(HippyResizeMode, (@{
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
HippyImageView *sIV = wIV;
|
||||
NSString *sURL = wURL;
|
||||
[sIV loadImage:animatedImage.posterImage url:sURL error:nil needBlur:YES needCache:NO];
|
||||
[sIV loadImage:animatedImage.posterImage url:sURL error:nil needBlur:YES];
|
||||
sIV.animatedImage = animatedImage;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -21,7 +21,13 @@
|
||||
*/
|
||||
|
||||
#import "HippyViewManager.h"
|
||||
#import "HippyImageDataLoaderProtocol.h"
|
||||
#import "HippyImageProviderProtocol.h"
|
||||
|
||||
@interface HippyImageViewManager : HippyViewManager
|
||||
|
||||
@property(nonatomic, strong)Class<HippyImageDataLoaderProtocol> imageDataLoaderClass;
|
||||
|
||||
@property(nonatomic, strong)Class<HippyImageProviderProtocol> imageProviderClass;
|
||||
|
||||
@end
|
||||
|
||||
@@ -23,9 +23,17 @@
|
||||
#import "HippyImageViewManager.h"
|
||||
#import "HippyImageView.h"
|
||||
#import "HippyConvert.h"
|
||||
#import "HippyBridge+LocalFileSource.h"
|
||||
#import "HippyImageDataLoader.h"
|
||||
#import "HippyDefaultImageProvider.h"
|
||||
#import "objc/runtime.h"
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface HippyImageViewManager () {
|
||||
NSMapTable<UIView *, id<HippyImageDataLoaderProtocol>> *_imageViewLoaderMapTable;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@implementation HippyImageViewManager
|
||||
|
||||
HIPPY_EXPORT_MODULE(Image)
|
||||
@@ -33,7 +41,6 @@ HIPPY_EXPORT_MODULE(Image)
|
||||
HIPPY_EXPORT_VIEW_PROPERTY(blurRadius, CGFloat)
|
||||
HIPPY_EXPORT_VIEW_PROPERTY(capInsets, UIEdgeInsets)
|
||||
HIPPY_EXPORT_VIEW_PROPERTY(resizeMode, HippyResizeMode)
|
||||
HIPPY_EXPORT_VIEW_PROPERTY(source, NSArray)
|
||||
HIPPY_EXPORT_VIEW_PROPERTY(onLoadStart, HippyDirectEventBlock)
|
||||
HIPPY_EXPORT_VIEW_PROPERTY(onProgress, HippyDirectEventBlock)
|
||||
HIPPY_EXPORT_VIEW_PROPERTY(onError, HippyDirectEventBlock)
|
||||
@@ -42,6 +49,37 @@ HIPPY_EXPORT_VIEW_PROPERTY(onLoad, HippyDirectEventBlock)
|
||||
HIPPY_EXPORT_VIEW_PROPERTY(onLoadEnd, HippyDirectEventBlock)
|
||||
HIPPY_EXPORT_VIEW_PROPERTY(downSample, BOOL)
|
||||
|
||||
HIPPY_CUSTOM_VIEW_PROPERTY(source, NSArray, HippyImageView) {
|
||||
NSArray *pathSources = [HippyConvert NSArray:json];
|
||||
if ([pathSources isKindOfClass:[NSArray class]]) {
|
||||
NSDictionary *dicSource = [pathSources firstObject];
|
||||
NSString *path = dicSource[@"uri"];
|
||||
id<HippyImageDataLoaderProtocol> imageDataLoader = [self imageDataLoaderForView:view];
|
||||
__weak HippyImageView *weakView = view;
|
||||
[imageDataLoader loadImageAtPath:path progress:^(NSUInteger current, NSUInteger total) {
|
||||
} completion:^(id result, NSString *path, NSError *error) {
|
||||
if (!error && weakView) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (weakView) {
|
||||
HippyImageView *strongView = weakView;
|
||||
if ([result isKindOfClass:[UIImage class]]) {
|
||||
[strongView updateImage:(UIImage *)result];
|
||||
}
|
||||
else if ([result isKindOfClass:[NSData class]]) {
|
||||
Class cls = [self imageProviderClass];
|
||||
id<HippyImageProviderProtocol> imageProvider = [[cls alloc] init];
|
||||
imageProvider.imageDataPath = path;
|
||||
[imageProvider setImageData:(NSData *)result];
|
||||
[strongView setImageProvider:imageProvider];
|
||||
[strongView reloadImage];
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
HIPPY_CUSTOM_VIEW_PROPERTY(tintColor, UIColor, HippyImageView) {
|
||||
view.tintColor = [HippyConvert UIColor:json] ?: defaultView.tintColor;
|
||||
view.renderingMode = json ? UIImageRenderingModeAlwaysTemplate : defaultView.renderingMode;
|
||||
@@ -49,25 +87,27 @@ HIPPY_CUSTOM_VIEW_PROPERTY(tintColor, UIColor, HippyImageView) {
|
||||
|
||||
HIPPY_CUSTOM_VIEW_PROPERTY(defaultSource, NSString, HippyImageView) {
|
||||
NSString *source = [HippyConvert NSString:json];
|
||||
if ([HippyBridge isHippyLocalFileURLString:source]) {
|
||||
NSString *localPath = [self.bridge absoluteStringFromHippyLocalFileURLString:source];
|
||||
BOOL isDirectory = NO;
|
||||
BOOL fileExist = [[NSFileManager defaultManager] fileExistsAtPath:localPath isDirectory:&isDirectory];
|
||||
if (fileExist && !isDirectory) {
|
||||
NSData *imageData = [NSData dataWithContentsOfFile:localPath];
|
||||
UIImage *image = [view imageFromData:imageData];
|
||||
view.defaultImage = image;
|
||||
id<HippyImageDataLoaderProtocol> imageDataLoader = [self imageDataLoaderForView:view];
|
||||
__weak HippyImageView *weakView = view;
|
||||
[imageDataLoader loadImageAtPath:source progress:^(NSUInteger current, NSUInteger total) {
|
||||
} completion:^(id result, NSString *path, NSError *error) {
|
||||
if (!error && weakView) {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (weakView) {
|
||||
HippyImageView *strongView = weakView;
|
||||
if ([result isKindOfClass:[NSData class]]) {
|
||||
Class cls = [self imageProviderClass];
|
||||
id<HippyImageProviderProtocol> imageProvider = [[cls alloc] init];
|
||||
[imageProvider setImageData:(NSData *)result];
|
||||
strongView.defaultImage = [imageProvider image];
|
||||
}
|
||||
else if ([result isKindOfClass:[UIImage class]]) {
|
||||
strongView.defaultImage = (UIImage *)result;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
else if ([source hasPrefix:@"data:image/"]) {
|
||||
NSRange range = [source rangeOfString:@";base64,"];
|
||||
if (NSNotFound != range.location) {
|
||||
source = [source substringFromIndex:range.location + range.length];
|
||||
}
|
||||
NSData *imageData = [[NSData alloc] initWithBase64EncodedString:source options:NSDataBase64DecodingIgnoreUnknownCharacters];
|
||||
UIImage *image = [view imageFromData:imageData];
|
||||
view.defaultImage = image;
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
#define HIPPY_VIEW_BORDER_RADIUS_PROPERTY(SIDE) \
|
||||
@@ -86,4 +126,47 @@ HIPPY_VIEW_BORDER_RADIUS_PROPERTY(BottomRight)
|
||||
return [[HippyImageView alloc] initWithBridge:self.bridge];
|
||||
}
|
||||
|
||||
- (Class<HippyImageDataLoaderProtocol>)imageDataLoaderClass {
|
||||
if (!_imageDataLoaderClass) {
|
||||
_imageDataLoaderClass = [HippyImageDataLoader class];
|
||||
}
|
||||
return _imageDataLoaderClass;
|
||||
}
|
||||
|
||||
- (Class<HippyImageProviderProtocol>)imageProviderClass {
|
||||
if (!_imageProviderClass) {
|
||||
_imageProviderClass = [HippyDefaultImageProvider class];
|
||||
}
|
||||
return _imageProviderClass;
|
||||
}
|
||||
|
||||
- (id<HippyImageDataLoaderProtocol>)getNewImageDataLoaderInstance {
|
||||
Class cls = [self imageDataLoaderClass];
|
||||
return [[cls alloc] init];
|
||||
}
|
||||
|
||||
- (id<HippyImageProviderProtocol>)getNewImageProviderInstance {
|
||||
Class cls = [self imageProviderClass];
|
||||
return [[cls alloc] init];
|
||||
}
|
||||
|
||||
- (NSMapTable *)imageViewLoaderMapTable {
|
||||
if (_imageViewLoaderMapTable) {
|
||||
_imageViewLoaderMapTable = [NSMapTable weakToStrongObjectsMapTable];
|
||||
}
|
||||
return _imageViewLoaderMapTable;
|
||||
}
|
||||
|
||||
- (id<HippyImageDataLoaderProtocol>)imageDataLoaderForView:(UIView *)view {
|
||||
id<HippyImageDataLoaderProtocol> loader = nil;
|
||||
if (view) {
|
||||
loader = objc_getAssociatedObject(view, @selector(imageDataLoaderForView:));
|
||||
if (!loader) {
|
||||
loader = [self getNewImageDataLoaderInstance];
|
||||
objc_setAssociatedObject(view, @selector(imageDataLoaderForView:), loader, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
|
||||
}
|
||||
}
|
||||
return loader;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
@@ -24,7 +24,6 @@
|
||||
#import "HippyBridge.h"
|
||||
#import "HippyImageLoaderModule.h"
|
||||
#import "HippyImageCacheManager.h"
|
||||
#import "HippyImageProviderProtocol.h"
|
||||
|
||||
@implementation HippyImageLoaderModule
|
||||
|
||||
@@ -34,52 +33,53 @@ HIPPY_EXPORT_MODULE(ImageLoaderModule)
|
||||
|
||||
// clang-format off
|
||||
HIPPY_EXPORT_METHOD(getSize:(NSString *)urlString resolver:(HippyPromiseResolveBlock)resolve rejecter:(HippyPromiseRejectBlock)reject) {
|
||||
UIImage *image = [[HippyImageCacheManager sharedInstance] loadImageFromCacheForURLString:urlString radius:0 isBlurredImage:nil];
|
||||
if (image) {
|
||||
NSDictionary *dic = @{@"width": @(image.size.width), @"height": @(image.size.height)};
|
||||
resolve(dic);
|
||||
return;
|
||||
}
|
||||
NSData *uriData = [urlString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
if (nil == uriData) {
|
||||
NSError *error = [NSError errorWithDomain:@"ImageLoaderModuleDomain" code:1 userInfo:@{@"reason": @"url parse error"}];
|
||||
reject(@"1", @"url parse error", error);
|
||||
return;
|
||||
}
|
||||
CFURLRef urlRef = CFURLCreateWithBytes(NULL, [uriData bytes], [uriData length], kCFStringEncodingUTF8, NULL);
|
||||
NSURL *source_url = CFBridgingRelease(urlRef);
|
||||
|
||||
typedef void (^HandleCompletedBlock)(BOOL, NSData *, NSURL *, NSError *);
|
||||
HandleCompletedBlock completedBlock = ^void(BOOL cached, NSData *data, NSURL *url, NSError *error) {
|
||||
if (error) {
|
||||
NSError *error = [NSError errorWithDomain:@"ImageLoaderModuleDomain" code:1 userInfo:@{@"reason": @"url parse error"}];
|
||||
reject(@"2", @"url request error", error);
|
||||
} else {
|
||||
if (!cached) {
|
||||
[[HippyImageCacheManager sharedInstance] setImageCacheData:data forURLString:urlString];
|
||||
}
|
||||
Class<HippyImageProviderProtocol> ipClass = imageProviderClassFromBridge(data,self.bridge);
|
||||
id<HippyImageProviderProtocol> instance = [ipClass imageProviderInstanceForData:data];
|
||||
UIImage *image = [instance image];
|
||||
if (image) {
|
||||
NSDictionary *dic = @{@"width": @(image.size.width), @"height": @(image.size.height)};
|
||||
resolve(dic);
|
||||
} else {
|
||||
NSError *error = [NSError errorWithDomain:@"ImageLoaderModuleDomain" code:2 userInfo:@{@"reason": @"image parse error"}];
|
||||
reject(@"2", @"image request error", error);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if (_bridge.imageLoader && [_bridge.imageLoader respondsToSelector: @selector(loadImage:completed:)]) {
|
||||
[_bridge.imageLoader loadImage: source_url completed:^(NSData *data, NSURL *url, NSError *error, BOOL cached) {
|
||||
completedBlock(cached, data, url, error);
|
||||
}];
|
||||
} else {
|
||||
[[[NSURLSession sharedSession] dataTaskWithURL:source_url completionHandler:^(NSData * _Nullable data, __unused NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
completedBlock(NO, data, source_url, error);
|
||||
}] resume];
|
||||
}
|
||||
//TODO complete this method
|
||||
// UIImage *image = [[HippyImageCacheManager sharedInstance] loadImageFromCacheForURLString:urlString radius:0 isBlurredImage:nil];
|
||||
// if (image) {
|
||||
// NSDictionary *dic = @{@"width": @(image.size.width), @"height": @(image.size.height)};
|
||||
// resolve(dic);
|
||||
// return;
|
||||
// }
|
||||
// NSData *uriData = [urlString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
// if (nil == uriData) {
|
||||
// NSError *error = [NSError errorWithDomain:@"ImageLoaderModuleDomain" code:1 userInfo:@{@"reason": @"url parse error"}];
|
||||
// reject(@"1", @"url parse error", error);
|
||||
// return;
|
||||
// }
|
||||
// CFURLRef urlRef = CFURLCreateWithBytes(NULL, [uriData bytes], [uriData length], kCFStringEncodingUTF8, NULL);
|
||||
// NSURL *source_url = CFBridgingRelease(urlRef);
|
||||
//
|
||||
// typedef void (^HandleCompletedBlock)(BOOL, NSData *, NSURL *, NSError *);
|
||||
// HandleCompletedBlock completedBlock = ^void(BOOL cached, NSData *data, NSURL *url, NSError *error) {
|
||||
// if (error) {
|
||||
// NSError *error = [NSError errorWithDomain:@"ImageLoaderModuleDomain" code:1 userInfo:@{@"reason": @"url parse error"}];
|
||||
// reject(@"2", @"url request error", error);
|
||||
// } else {
|
||||
// if (!cached) {
|
||||
// [[HippyImageCacheManager sharedInstance] setImageCacheData:data forURLString:urlString];
|
||||
// }
|
||||
// Class<HippyImageProviderProtocol> ipClass = imageProviderClassFromBridge(data,self.bridge);
|
||||
// id<HippyImageProviderProtocol> instance = [ipClass imageProviderInstanceForData:data];
|
||||
// UIImage *image = [instance image];
|
||||
// if (image) {
|
||||
// NSDictionary *dic = @{@"width": @(image.size.width), @"height": @(image.size.height)};
|
||||
// resolve(dic);
|
||||
// } else {
|
||||
// NSError *error = [NSError errorWithDomain:@"ImageLoaderModuleDomain" code:2 userInfo:@{@"reason": @"image parse error"}];
|
||||
// reject(@"2", @"image request error", error);
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// if (_bridge.imageLoader && [_bridge.imageLoader respondsToSelector: @selector(loadImage:completed:)]) {
|
||||
// [_bridge.imageLoader loadImage: source_url completed:^(NSData *data, NSURL *url, NSError *error, BOOL cached) {
|
||||
// completedBlock(cached, data, url, error);
|
||||
// }];
|
||||
// } else {
|
||||
// [[[NSURLSession sharedSession] dataTaskWithURL:source_url completionHandler:^(NSData * _Nullable data, __unused NSURLResponse * _Nullable response, NSError * _Nullable error) {
|
||||
// completedBlock(NO, data, source_url, error);
|
||||
// }] resume];
|
||||
// }
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -515,7 +515,7 @@ BOOL HippyIsLocalAssetURL(NSURL *__nullable imageURL) {
|
||||
return [extension isEqualToString:@"png"] || [extension isEqualToString:@"jpg"];
|
||||
}
|
||||
|
||||
HIPPY_EXTERN NSString *__nullable HippyTempFilePath(NSString *extension, NSError **error) {
|
||||
NSString *__nullable HippyTempFilePath(NSString *extension, NSError **error) {
|
||||
static NSError *setupError = nil;
|
||||
static NSString *directory;
|
||||
static dispatch_once_t onceToken;
|
||||
@@ -695,7 +695,7 @@ UIColor *HippyConvertStringToColor(NSString *colorString) {
|
||||
return color;
|
||||
}
|
||||
|
||||
HIPPY_EXTERN UIColor *HippyConvertNumberToColor(NSInteger colorNumber) {
|
||||
UIColor *HippyConvertNumberToColor(NSInteger colorNumber) {
|
||||
NSInteger a = (colorNumber >> 24) & 0xFF;
|
||||
NSInteger r = (colorNumber >> 16) & 0xFF;
|
||||
NSInteger g = (colorNumber >> 8) & 0xFF;
|
||||
@@ -765,15 +765,18 @@ NSURL *__nullable HippyURLByReplacingQueryParam(NSURL *__nullable URL, NSString
|
||||
NSURL *__nullable HippyURLWithString(NSString *URLString, NSString *baseURLString) {
|
||||
if (URLString) {
|
||||
NSURL *baseURL = HippyURLWithString(baseURLString, NULL);
|
||||
CFURLRef URLRef = CFURLCreateWithString(NULL, (CFStringRef)URLString, (CFURLRef)baseURL);
|
||||
if (URLRef) {
|
||||
return CFBridgingRelease(URLRef);
|
||||
NSData *uriData = [URLString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
if (nil == uriData) {
|
||||
return nil;
|
||||
}
|
||||
CFURLRef urlRef = CFURLCreateWithBytes(NULL, [uriData bytes], [uriData length], kCFStringEncodingUTF8, (__bridge CFURLRef)baseURL);
|
||||
NSURL *source_url = CFBridgingRelease(urlRef);
|
||||
return source_url;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
HIPPY_EXTERN NSStringEncoding HippyGetStringEncodingFromURLResponse(NSURLResponse *response) {
|
||||
NSStringEncoding HippyGetStringEncodingFromURLResponse(NSURLResponse *response) {
|
||||
NSString *textEncoding = [response textEncodingName];
|
||||
if (!textEncoding) {
|
||||
return NSUTF8StringEncoding;
|
||||
|
||||
@@ -127,7 +127,6 @@ using HPViewBinding = std::unordered_map<int32_t, std::tuple<std::vector<int32_t
|
||||
static void HippyTraverseViewNodes(id<HippyComponent> view, void (^block)(id<HippyComponent>)) {
|
||||
if (view.hippyTag) {
|
||||
block(view);
|
||||
|
||||
for (id<HippyComponent> subview in view.hippySubviews) {
|
||||
HippyTraverseViewNodes(subview, block);
|
||||
}
|
||||
@@ -462,7 +461,6 @@ dispatch_queue_t HippyGetUIManagerQueue(void) {
|
||||
[(id<HippyInvalidating>)subview invalidate];
|
||||
}
|
||||
[registry removeObjectForKey:subview.hippyTag];
|
||||
|
||||
if (registry == (NSMutableDictionary<NSNumber *, id<HippyComponent>> *)self->_viewRegistry) {
|
||||
[self->_bridgeTransactionListeners removeObject:subview];
|
||||
}
|
||||
@@ -470,28 +468,6 @@ dispatch_queue_t HippyGetUIManagerQueue(void) {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disassociates children from container. Doesn't remove from registries.
|
||||
* @returns Array of removed items.
|
||||
*/
|
||||
- (NSArray<id<HippyComponent>> *)childrenToRemoveFromContainer:(id<HippyComponent>)container atIndices:(NSArray<NSNumber *> *)atIndices {
|
||||
// If there are no indices to move or the container has no subviews don't bother
|
||||
// We support parents with nil subviews so long as they're all nil so this allows for this behavior
|
||||
if (atIndices.count == 0 || [container hippySubviews].count == 0) {
|
||||
return nil;
|
||||
}
|
||||
// Construction of removed children must be done "up front", before indices are disturbed by removals.
|
||||
NSMutableArray<id<HippyComponent>> *removedChildren = [NSMutableArray arrayWithCapacity:atIndices.count];
|
||||
HippyAssert(container != nil, @"container view (for ID %@) not found", container);
|
||||
for (NSNumber *indexNumber in atIndices) {
|
||||
NSUInteger index = indexNumber.unsignedIntegerValue;
|
||||
if (index < [container hippySubviews].count) {
|
||||
[removedChildren addObject:[container hippySubviews][index]];
|
||||
}
|
||||
}
|
||||
return removedChildren;
|
||||
}
|
||||
|
||||
- (void)removeChildren:(NSArray<id<HippyComponent>> *)children fromContainer:(id<HippyComponent>)container {
|
||||
for (id<HippyComponent> removedChild in children) {
|
||||
[container removeHippySubview:removedChild];
|
||||
@@ -884,14 +860,14 @@ dispatch_queue_t HippyGetUIManagerQueue(void) {
|
||||
int32_t tag = dom_node->GetId();
|
||||
HippyShadowView *shadowView = _shadowViewRegistry[@(tag)];
|
||||
[shadowView removeFromHippySuperview];
|
||||
[_shadowViewRegistry removeObjectForKey:@(tag)];
|
||||
[self purgeChildren:@[shadowView] fromRegistry:(NSMutableDictionary<NSNumber *, id<HippyComponent>> *)_shadowViewRegistry];
|
||||
__weak auto weakSelf = self;
|
||||
[self addUIBlock:^(HippyUIManager *uiManager, NSDictionary<NSNumber *,__kindof UIView *> *viewRegistry) {
|
||||
UIView *view = viewRegistry[@(tag)];
|
||||
[view removeFromHippySuperview];
|
||||
if (weakSelf) {
|
||||
auto strongSelf = weakSelf;
|
||||
[strongSelf->_viewRegistry removeObjectForKey:@(tag)];
|
||||
[strongSelf purgeChildren:@[view] fromRegistry:(NSMutableDictionary<NSNumber *, id<HippyComponent>> *)(strongSelf->_viewRegistry)];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user