From c2927bb15b0e844ae702c15766384c55fd317b82 Mon Sep 17 00:00:00 2001 From: wwwcg Date: Thu, 12 Sep 2024 20:59:41 +0800 Subject: [PATCH] refactor(ios): rewrite bundle loading process (#4028) --- framework/ios/base/bridge/HippyBridge.mm | 226 +++++++-------- .../HippyBundleExecutionOperation.h | 33 --- .../HippyBundleExecutionOperation.m | 258 ------------------ .../HippyBundleLoadOperation.h | 39 --- .../HippyBundleLoadOperation.mm | 207 -------------- .../HippyBundleOperationQueue.h | 33 --- .../HippyBundleOperationQueue.m | 87 ------ 7 files changed, 118 insertions(+), 765 deletions(-) delete mode 100644 framework/ios/base/bundleoperations/HippyBundleExecutionOperation.h delete mode 100644 framework/ios/base/bundleoperations/HippyBundleExecutionOperation.m delete mode 100644 framework/ios/base/bundleoperations/HippyBundleLoadOperation.h delete mode 100644 framework/ios/base/bundleoperations/HippyBundleLoadOperation.mm delete mode 100644 framework/ios/base/bundleoperations/HippyBundleOperationQueue.h delete mode 100644 framework/ios/base/bundleoperations/HippyBundleOperationQueue.m diff --git a/framework/ios/base/bridge/HippyBridge.mm b/framework/ios/base/bridge/HippyBridge.mm index e89b6e9ccbd..df7dea8be9b 100644 --- a/framework/ios/base/bridge/HippyBridge.mm +++ b/framework/ios/base/bridge/HippyBridge.mm @@ -22,9 +22,6 @@ #import "HippyBridge.h" #import "HippyBridge+Private.h" -#import "HippyBundleLoadOperation.h" -#import "HippyBundleExecutionOperation.h" -#import "HippyBundleOperationQueue.h" #import "HippyDeviceBaseInfo.h" #import "HippyDisplayLink.h" #import "HippyEventDispatcher.h" @@ -49,6 +46,7 @@ #import "HippyUtils.h" #import "TypeConverter.h" #import "VFSUriLoader.h" +#import "HippyBridge+VFSLoader.h" #import "HippyBase64DataHandler.h" #import "NativeRenderManager.h" #import "HippyRootView.h" @@ -109,6 +107,10 @@ static NSString *const kHippyBatchedBridgeConfigKey = @"__hpBatchedBridgeConfig"; +#define HIPPY_BUNDLE_FETCH_TIMEOUT_SEC 30 // Bundle fetch operation timeout value, 30s +static NSString *const kHippyBundleFetchQueueName = @"com.hippy.bundleQueue.fetch"; +static NSString *const kHippyBundleExecuteQueueName = @"com.hippy.bundleQueue.execute"; + typedef NS_ENUM(NSUInteger, HippyBridgeFields) { HippyBridgeFieldRequestModuleIDs = 0, HippyBridgeFieldMethodIDs, @@ -148,12 +150,10 @@ static inline void registerLogDelegateToHippyCore() { @interface HippyBridge() { __weak id _methodInterceptor; HippyModulesSetup *_moduleSetup; - __weak NSOperation *_lastOperation; BOOL _wasBatchActive; HippyDisplayLink *_displayLink; HippyBridgeModuleProviderBlock _moduleProvider; BOOL _valid; - HippyBundleOperationQueue *_bundlesQueue; NSMutableArray *_bundleURLs; std::shared_ptr _uriLoader; @@ -173,14 +173,19 @@ @interface HippyBridge() { /// 在共享情况下,只有全部bridge实例均释放,JS引擎资源才会销毁。 /// 默认情况下对每个bridge使用独立JS引擎 @property (nonatomic, strong) NSString *engineKey; -/// 等待加载(Load)的 Vendor bundleURL -@property (nonatomic, strong) NSURL *pendingLoadingVendorBundleURL; - -@property(readwrite, strong) dispatch_semaphore_t moduleSemaphore; -@property(readwrite, assign) NSInteger loadingCount; - +/// Module setup semaphore +@property (readwrite, strong) dispatch_semaphore_t moduleSemaphore; -/// 缓存的Dimensions信息,用于传递给JS Side +/// Pending load bundle's URL +@property (nonatomic, strong) NSURL *pendingLoadingVendorBundleURL; +/// Bundle loading count, used to indicate whether is in loading state. +@property (nonatomic, assign) NSInteger loadingCount; +/// Bundle fetch operation queue (concurrent) +@property (nonatomic, strong) NSOperationQueue *bundleQueue; +/// Record the last execute operation for adding execution dependency. +@property (atomic, strong, nullable) NSOperation *lastExecuteOperation; + +/// Cached Dimensions info,will be passed to JS Side. @property (atomic, strong) NSDictionary *cachedDimensionsInfo; @end @@ -193,17 +198,6 @@ @implementation HippyBridge dispatch_queue_t HippyJSThread; -dispatch_queue_t HippyBridgeQueue() { - static dispatch_once_t onceToken; - static dispatch_queue_t queue; - dispatch_once(&onceToken, ^{ - dispatch_queue_attr_t attr = - dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_USER_INITIATED, 0); - queue = dispatch_queue_create("com.hippy.bridge", attr); - }); - return queue; -} - + (void)initialize { [super initialize]; static dispatch_once_t onceToken; @@ -238,13 +232,16 @@ - (instancetype)initWithDelegate:(id)delegate _debugMode = [launchOptions[@"DebugMode"] boolValue]; _enableTurbo = !!launchOptions[@"EnableTurbo"] ? [launchOptions[@"EnableTurbo"] boolValue] : YES; _engineKey = executorKey.length > 0 ? executorKey : [NSString stringWithFormat:@"%p", self]; - _bundlesQueue = [[HippyBundleOperationQueue alloc] init]; - HippyLogInfo(@"HippyBridge init begin, self:%p", self); - // Set the log delegate for hippy core module registerLogDelegateToHippyCore(); + // Create bundle operation queue + _bundleQueue = [[NSOperationQueue alloc] init]; + _bundleQueue.qualityOfService = NSQualityOfServiceUserInitiated; + _bundleQueue.name = kHippyBundleFetchQueueName; + _bundleQueue.maxConcurrentOperationCount = NSOperationQueueDefaultMaxConcurrentOperationCount; + // Setup [self setUp]; @@ -462,6 +459,7 @@ - (void)setUp { } @catch (NSException *exception) { HippyBridgeHandleException(exception, self); + dispatch_semaphore_signal(self.moduleSemaphore); } [self addImageProviderClass:[HippyDefaultImageProvider class]]; @@ -491,13 +489,13 @@ - (void)loadPendingVendorBundleURLIfNeeded { } } -#define BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO \ - @{ kHippyNotiBridgeKey: strongSelf, \ +#define BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO(whichSelf) \ + @{ kHippyNotiBridgeKey: whichSelf, \ kHippyNotiBundleUrlKey: bundleURL, \ kHippyNotiBundleTypeKey : @(bundleType) } -#define BUNDLE_LOAD_NOTI_ERROR_USER_INFO \ - @{ kHippyNotiBridgeKey: strongSelf, \ +#define BUNDLE_LOAD_NOTI_ERROR_USER_INFO(whichSelf) \ + @{ kHippyNotiBridgeKey: whichSelf, \ kHippyNotiBundleUrlKey: bundleURL, \ kHippyNotiBundleTypeKey : @(bundleType), \ kHippyNotiErrorKey : error } @@ -505,6 +503,7 @@ - (void)loadPendingVendorBundleURLIfNeeded { - (void)loadBundleURL:(NSURL *)bundleURL bundleType:(HippyBridgeBundleType)bundleType completion:(nonnull HippyBridgeBundleLoadCompletionBlock)completion { + HippyAssertParam(bundleURL); if (!bundleURL) { if (completion) { static NSString *bundleError = @"bundle url is nil"; @@ -529,117 +528,108 @@ - (void)loadBundleURL:(NSURL *)bundleURL HP_CSTR_NOT_NULL(bundleURL.absoluteString.UTF8String)); [_bundleURLs addObject:bundleURL]; - __weak __typeof(self)weakSelf = self; - dispatch_async(HippyBridgeQueue(), ^{ - __strong __typeof(weakSelf)strongSelf = weakSelf; - if (!strongSelf) { - return; - } - NSDictionary *userInfo = BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO; - [[NSNotificationCenter defaultCenter] postNotificationName:HippyJavaScriptWillStartLoadingNotification - object:strongSelf - userInfo:userInfo]; - [strongSelf beginLoadingBundle:bundleURL bundleType:bundleType completion:completion]; - }); + NSDictionary *userInfo = BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO(self); + [[NSNotificationCenter defaultCenter] postNotificationName:HippyJavaScriptWillStartLoadingNotification + object:self + userInfo:userInfo]; + [self beginLoadingBundle:bundleURL bundleType:bundleType completion:completion]; } - (void)beginLoadingBundle:(NSURL *)bundleURL bundleType:(HippyBridgeBundleType)bundleType completion:(HippyBridgeBundleLoadCompletionBlock)completion { - dispatch_group_t group = dispatch_group_create(); - __weak HippyBridge *weakSelf = self; + HippyAssertMainQueue(); + HippyAssertParam(bundleURL); + HippyAssertParam(completion); + + __weak __typeof(self)weakSelf = self; __block NSData *script = nil; self.loadingCount++; - dispatch_group_enter(group); - NSOperationQueue *bundleQueue = [[NSOperationQueue alloc] init]; - bundleQueue.maxConcurrentOperationCount = 1; - bundleQueue.name = @"com.hippy.bundleQueue"; - HippyBundleLoadOperation *fetchOp = [[HippyBundleLoadOperation alloc] initWithBridge:self - bundleURL:bundleURL - queue:bundleQueue]; - fetchOp.onLoad = ^(NSData *source, NSError *error) { - __strong __typeof(weakSelf)strongSelf = weakSelf; + + // Fetch operation + NSBlockOperation *fetchOperation = [NSBlockOperation blockOperationWithBlock:^{ + __strong __typeof(weakSelf) strongSelf = weakSelf; if (!strongSelf) { - dispatch_group_leave(group); return; } - NSDictionary *userInfo; - if (error) { - HippyBridgeFatal(error, weakSelf); - userInfo = BUNDLE_LOAD_NOTI_ERROR_USER_INFO; - } else { - script = source; - userInfo = BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO; + HippyLogInfo(@"Start fetching bundle(%s)", + HP_CSTR_NOT_NULL(bundleURL.absoluteString.lastPathComponent.UTF8String)); + // create semaphore + dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); + [strongSelf fetchBundleWithURL:bundleURL completion:^(NSData *source, NSError *error) { + __strong __typeof(weakSelf)strongSelf = weakSelf; + NSDictionary *userInfo; + if (error) { + HippyBridgeFatal(error, strongSelf); + userInfo = BUNDLE_LOAD_NOTI_ERROR_USER_INFO(strongSelf); + } else { + script = source; + userInfo = BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO(strongSelf); + } + [[NSNotificationCenter defaultCenter] postNotificationName:HippyJavaScripDidLoadSourceCodeNotification + object:strongSelf + userInfo:userInfo]; + HippyLogInfo(@"End fetching bundle(%s) error?:%@", + HP_CSTR_NOT_NULL(bundleURL.absoluteString.lastPathComponent.UTF8String), error); + dispatch_semaphore_signal(semaphore); // release semaphore + }]; + // wait semaphore + dispatch_time_t timeout = dispatch_time(DISPATCH_TIME_NOW, HIPPY_BUNDLE_FETCH_TIMEOUT_SEC * NSEC_PER_SEC); + intptr_t result = dispatch_semaphore_wait(semaphore, timeout); + if (result != 0) { + HippyLogError(@"Fetch operation timed out!!! (30s)"); } - [[NSNotificationCenter defaultCenter] postNotificationName:HippyJavaScripDidLoadSourceCodeNotification - object:strongSelf - userInfo:userInfo]; - dispatch_group_leave(group); - }; + }]; - dispatch_group_enter(group); - HippyBundleExecutionOperation *executeOp = [[HippyBundleExecutionOperation alloc] initWithBlock:^{ - __strong __typeof(weakSelf)strongSelf = weakSelf; - if (!strongSelf || !strongSelf.valid) { - dispatch_group_leave(group); + // Execution operation + NSBlockOperation *executeOperation = [NSBlockOperation blockOperationWithBlock:^{ + HippyLogInfo(@"Start executing bundle(%s)", + HP_CSTR_NOT_NULL(bundleURL.absoluteString.lastPathComponent.UTF8String)); + __strong __typeof(weakSelf) strongSelf = weakSelf; + if (!strongSelf || !strongSelf.valid || !script) { + NSString *errMsg = [NSString stringWithFormat:@"Bundle Execution Operation Fail! valid:%d, script:%@", + strongSelf.valid, script]; + completion(nil, HippyErrorWithMessage(errMsg)); + strongSelf.lastExecuteOperation = nil; return; } - __weak __typeof(strongSelf)weakSelf = strongSelf; [strongSelf executeJSCode:script sourceURL:bundleURL onCompletion:^(id result, NSError *error) { - __strong __typeof(weakSelf)strongSelf = weakSelf; - HippyLogInfo(@"End loading bundle(%s) at %s", - HP_CSTR_NOT_NULL(bundleURL.absoluteString.lastPathComponent.UTF8String), - HP_CSTR_NOT_NULL(bundleURL.absoluteString.UTF8String)); - + HippyLogInfo(@"End executing bundle(%s)", + HP_CSTR_NOT_NULL(bundleURL.absoluteString.lastPathComponent.UTF8String)); + strongSelf.lastExecuteOperation = nil; if (completion) { completion(bundleURL, error); } if (!strongSelf || !strongSelf.valid) { - dispatch_group_leave(group); return; } if (error) { HippyBridgeFatal(error, strongSelf); } - __weak __typeof(self)weakSelf = strongSelf; + dispatch_async(dispatch_get_main_queue(), ^{ __strong __typeof(weakSelf)strongSelf = weakSelf; if (!strongSelf) { return; } - NSNotificationName notiName; - NSDictionary *userInfo; - if (error) { - notiName = HippyJavaScriptDidFailToLoadNotification; - userInfo = BUNDLE_LOAD_NOTI_ERROR_USER_INFO; - } else { - notiName = HippyJavaScriptDidLoadNotification; - userInfo = BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO; - } - [[NSNotificationCenter defaultCenter] postNotificationName:notiName - object:strongSelf - userInfo:userInfo]; + strongSelf.loadingCount--; + NSNotificationName notiName = error ? HippyJavaScriptDidFailToLoadNotification : HippyJavaScriptDidLoadNotification; + NSDictionary *userInfo = error ? BUNDLE_LOAD_NOTI_ERROR_USER_INFO(strongSelf) : BUNDLE_LOAD_NOTI_SUCCESS_USER_INFO(strongSelf); + [[NSNotificationCenter defaultCenter] postNotificationName:notiName object:strongSelf userInfo:userInfo]; }); - dispatch_group_leave(group); }]; - } queue:bundleQueue]; + }]; - //set dependency - [executeOp addDependency:fetchOp]; - if (_lastOperation) { - [executeOp addDependency:_lastOperation]; - _lastOperation = executeOp; - } else { - _lastOperation = executeOp; + // Add dependency, make sure that doing fetch before execute, + // and all execution operations must be queued. + [executeOperation addDependency:fetchOperation]; + if (self.lastExecuteOperation) { + [executeOperation addDependency:self.lastExecuteOperation]; } - [_bundlesQueue addOperations:@[fetchOp, executeOp]]; - dispatch_block_t completionBlock = ^(void){ - HippyBridge *strongSelf = weakSelf; - if (strongSelf && strongSelf.isValid) { - strongSelf.loadingCount--; - } - }; - dispatch_group_notify(group, HippyBridgeQueue(), completionBlock); + + // Enqueue operation + [_bundleQueue addOperations:@[fetchOperation, executeOperation] waitUntilFinished:NO]; + self.lastExecuteOperation = executeOperation; } - (void)unloadInstanceForRootView:(NSNumber *)rootTag { @@ -703,6 +693,26 @@ - (void)setInspectable:(BOOL)isInspectable { #pragma mark - Private +/// Fetch JS Bundle +- (void)fetchBundleWithURL:(NSURL *)bundleURL completion:(void (^)(NSData *source, NSError *error))completion { + HippyAssertParam(bundleURL); + HippyAssertParam(completion); + // Fetch the bundle + // Call the completion handler with the fetched data or error + [self loadContentsAsynchronouslyFromUrl:bundleURL.absoluteString + method:@"get" + params:nil + body:nil + queue:nil + progress:nil + completionHandler:^(NSData * _Nullable data, + NSDictionary * _Nullable userInfo, + NSURLResponse * _Nullable response, + NSError * _Nullable error) { + completion(data, error); + }]; +} + /// Execute JS Bundle - (void)executeJSCode:(NSData *)script sourceURL:(NSURL *)sourceURL diff --git a/framework/ios/base/bundleoperations/HippyBundleExecutionOperation.h b/framework/ios/base/bundleoperations/HippyBundleExecutionOperation.h deleted file mode 100644 index c3ccecd4de5..00000000000 --- a/framework/ios/base/bundleoperations/HippyBundleExecutionOperation.h +++ /dev/null @@ -1,33 +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 - -NS_ASSUME_NONNULL_BEGIN - -@interface HippyBundleExecutionOperation : NSOperation - -- (instancetype)initWithBlock:(dispatch_block_t)block queue:(NSOperationQueue *)queue; - -@end - -NS_ASSUME_NONNULL_END diff --git a/framework/ios/base/bundleoperations/HippyBundleExecutionOperation.m b/framework/ios/base/bundleoperations/HippyBundleExecutionOperation.m deleted file mode 100644 index db2b62ab1e1..00000000000 --- a/framework/ios/base/bundleoperations/HippyBundleExecutionOperation.m +++ /dev/null @@ -1,258 +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 "HippyBundleExecutionOperation.h" - -@interface HippyBundleExecutionOperation () { - dispatch_block_t _block; - BOOL _cancelled; - BOOL _executing; - BOOL _finished; - BOOL _asynchronous; - BOOL _ready; - NSMutableSet *_dependencies; - - dispatch_semaphore_t _statusSem; - dispatch_semaphore_t _dependencySem; -} - -@end - -@implementation HippyBundleExecutionOperation - -- (instancetype)initWithBlock:(dispatch_block_t)block queue:(NSOperationQueue *)queue { - self = [super init]; - if (self) { - _block = [block copy]; - _dependencies = [NSMutableSet setWithCapacity:8]; - _statusSem = dispatch_semaphore_create(1); - _dependencySem = dispatch_semaphore_create(1); - self.ready = YES; - } - return self; -} - -- (void)dealloc { - dispatch_semaphore_wait(_dependencySem, DISPATCH_TIME_FOREVER); - for (NSOperation *op in _dependencies) { - [op removeObserver:self forKeyPath:@"finished" context:NULL]; - } - dispatch_semaphore_signal(_dependencySem); -} - -- (void)start { - if (self.cancelled) { - return; - } - if (self.ready) { - [self main]; - } -} - -- (void)main { - if (self.cancelled) { - return; - } - self.finished = NO; - self.executing = YES; - if (_block) { - _block(); - } - self.finished = YES; - self.executing = NO; -} - -- (void)addDependency:(NSOperation *)op { - if (self.cancelled || self.executing || self.finished || !op) { - return; - } - { - dispatch_semaphore_wait(_dependencySem, DISPATCH_TIME_FOREVER); - [_dependencies addObject:op]; - dispatch_semaphore_signal(_dependencySem); - } - if (![op isFinished]) { - self.ready = NO; - } - [op addObserver:self forKeyPath:@"finished" options:NSKeyValueObservingOptionNew context:NULL]; -} - -- (void)removeDependency:(NSOperation *)op { - dispatch_semaphore_wait(_dependencySem, DISPATCH_TIME_FOREVER); - if ([_dependencies containsObject:op]) { - [_dependencies removeObject:op]; - [op removeObserver:self forKeyPath:@"finished" context:NULL]; - } - dispatch_semaphore_signal(_dependencySem); -} - -- (NSArray *)dependencies { - dispatch_semaphore_wait(_dependencySem, DISPATCH_TIME_FOREVER); - NSArray *objects = [_dependencies allObjects]; - dispatch_semaphore_signal(_dependencySem); - return objects; -} - -- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { - if ([keyPath isEqualToString:@"finished"]) { - [self checkForReadyStatus]; - } -} - -- (void)checkForReadyStatus { - dispatch_semaphore_wait(_dependencySem, DISPATCH_TIME_FOREVER); - BOOL status = YES; - for (NSOperation *op in _dependencies) { - if (![op isFinished]) { - status = NO; - break; - } - } - self.ready = status; - dispatch_semaphore_signal(_dependencySem); -} - -- (void)cancel { - self.cancelled = YES; -} - -- (void)setCancelled:(BOOL)cancelled { - if (_cancelled == cancelled) { - return; - } - [self willChangeValueForKey:@"cancelled"]; - { - dispatch_semaphore_wait(_statusSem, DISPATCH_TIME_FOREVER); - _cancelled = cancelled; - dispatch_semaphore_signal(_statusSem); - } - [self didChangeValueForKey:@"cancelled"]; -} - -- (BOOL)isCancelled { - dispatch_semaphore_wait(_statusSem, DISPATCH_TIME_FOREVER); - BOOL cancel = _cancelled; - dispatch_semaphore_signal(_statusSem); - return cancel; -} - -- (void)setExecuting:(BOOL)isExecuting { - if (_executing == isExecuting) { - return; - } - [self willChangeValueForKey:@"executing"]; - { - dispatch_semaphore_wait(_statusSem, DISPATCH_TIME_FOREVER); - _executing = isExecuting; - dispatch_semaphore_signal(_statusSem); - } - [self didChangeValueForKey:@"executing"]; -} - -- (BOOL)isExecuting { - dispatch_semaphore_wait(_statusSem, DISPATCH_TIME_FOREVER); - BOOL executing = _executing; - dispatch_semaphore_signal(_statusSem); - return executing; -} - -- (void)setFinished:(BOOL)isFinished { - if (_finished == isFinished) { - return; - } - [self willChangeValueForKey:@"finished"]; - { - dispatch_semaphore_wait(_statusSem, DISPATCH_TIME_FOREVER); - _finished = isFinished; - dispatch_semaphore_signal(_statusSem); - } - [self didChangeValueForKey:@"finished"]; -} - -- (BOOL)isFinished { - dispatch_semaphore_wait(_statusSem, DISPATCH_TIME_FOREVER); - BOOL finished = _finished; - dispatch_semaphore_signal(_statusSem); - return finished; -} - -- (void)setConcurrent:(BOOL)isConcurrent { - if (_asynchronous == isConcurrent) { - return; - } - [self willChangeValueForKey:@"concurrent"]; - { - dispatch_semaphore_wait(_statusSem, DISPATCH_TIME_FOREVER); - _asynchronous = isConcurrent; - dispatch_semaphore_signal(_statusSem); - } - [self didChangeValueForKey:@"concurrent"]; -} - -- (BOOL)isConcurrent { - dispatch_semaphore_wait(_statusSem, DISPATCH_TIME_FOREVER); - BOOL asynchronous = _asynchronous; - dispatch_semaphore_signal(_statusSem); - return asynchronous; -} - -- (void)setAsynchronous:(BOOL)isAsynchronous { - if (_asynchronous == isAsynchronous) { - return; - } - [self willChangeValueForKey:@"asynchronous"]; - { - dispatch_semaphore_wait(_statusSem, DISPATCH_TIME_FOREVER); - _asynchronous = isAsynchronous; - dispatch_semaphore_signal(_statusSem); - } - [self didChangeValueForKey:@"asynchronous"]; -} - -- (BOOL)isAsynchronous { - dispatch_semaphore_wait(_statusSem, DISPATCH_TIME_FOREVER); - BOOL asynchronous = _asynchronous; - dispatch_semaphore_signal(_statusSem); - return asynchronous; -} - -- (void)setReady:(BOOL)isReady { - if (_ready == isReady) { - return; - } - [self willChangeValueForKey:@"ready"]; - { - dispatch_semaphore_wait(_statusSem, DISPATCH_TIME_FOREVER); - _ready = isReady; - dispatch_semaphore_signal(_statusSem); - } - [self didChangeValueForKey:@"ready"]; -} - -- (BOOL)isReady { - dispatch_semaphore_wait(_statusSem, DISPATCH_TIME_FOREVER); - BOOL ready = _ready; - dispatch_semaphore_signal(_statusSem); - return ready; -} - -@end diff --git a/framework/ios/base/bundleoperations/HippyBundleLoadOperation.h b/framework/ios/base/bundleoperations/HippyBundleLoadOperation.h deleted file mode 100644 index 9d4e2a96449..00000000000 --- a/framework/ios/base/bundleoperations/HippyBundleLoadOperation.h +++ /dev/null @@ -1,39 +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 - -NS_ASSUME_NONNULL_BEGIN - -@class HippyBridge; - -typedef void (^HippyBundleLoadCompletionBlock)(NSData *, NSError *); - -@interface HippyBundleLoadOperation : NSOperation - -@property(nonatomic, copy) HippyBundleLoadCompletionBlock onLoad; - -- (instancetype)initWithBridge:(HippyBridge *)bridge bundleURL:(NSURL *)bundleURL queue:(NSOperationQueue *)queue; - -@end - -NS_ASSUME_NONNULL_END diff --git a/framework/ios/base/bundleoperations/HippyBundleLoadOperation.mm b/framework/ios/base/bundleoperations/HippyBundleLoadOperation.mm deleted file mode 100644 index 02594550199..00000000000 --- a/framework/ios/base/bundleoperations/HippyBundleLoadOperation.mm +++ /dev/null @@ -1,207 +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 "HippyBundleLoadOperation.h" -#import "HippyBridge+VFSLoader.h" - -#include - -@interface HippyBundleLoadOperation () { - HippyBridge *_bridge; - NSURL *_bundleURL; - - BOOL _cancelled; - BOOL _executing; - BOOL _finished; - BOOL _asynchronous; - BOOL _ready; - std::mutex _statusMutex; - NSOperationQueue *_finishQueue; -} - -@end - -@implementation HippyBundleLoadOperation - -@synthesize finished = _finished; -@synthesize executing = _executing; - -- (instancetype)initWithBridge:(HippyBridge *)bridge bundleURL:(NSURL *)bundleURL queue:(NSOperationQueue *)queue { - self = [super init]; - if (self) { - _bridge = bridge; - _bundleURL = bundleURL; - _finishQueue = queue; - self.ready = YES; - } - return self; -} - -- (void)start { - self.asynchronous = YES; - self.concurrent = YES; - [self main]; -} - -- (void)main { - if (self.cancelled) { - return; - } - self.finished = NO; - self.executing = YES; - HippyBridge *bridge = _bridge; - NSString *bundleURL = [_bundleURL absoluteString]; - __weak HippyBundleLoadOperation *weakSelf = self; - [bridge loadContentsAsynchronouslyFromUrl:bundleURL - method:@"get" - params:nil - body:nil - queue:_finishQueue - progress:nil - completionHandler:^(NSData * _Nullable data, - NSDictionary * _Nullable userInfo, - NSURLResponse * _Nullable response, - NSError * _Nullable error) { - HippyBundleLoadOperation *strongSelf = weakSelf; - if (!strongSelf || strongSelf.cancelled) { - strongSelf.finished = YES; - strongSelf.executing = NO; - return; - } - if (strongSelf.onLoad) { - strongSelf.onLoad(data, error); - } - strongSelf.finished = YES; - strongSelf.executing = NO; - }]; -} - -- (void)cancel { - self.cancelled = YES; -} - -- (void)setCancelled:(BOOL)cancelled { - if (_cancelled == cancelled) { - return; - } - [self willChangeValueForKey:@"isCancelled"]; - { - std::lock_guard lock(_statusMutex); - _cancelled = cancelled; - } - [self didChangeValueForKey:@"isCancelled"]; -} - -- (BOOL)isCancelled { - std::lock_guard lock(_statusMutex); - return _cancelled; -} - -- (void)setExecuting:(BOOL)isExecuting { - if (_executing == isExecuting) { - return; - } - [self willChangeValueForKey:@"isExecuting"]; - { - std::lock_guard lock(_statusMutex); - _executing = isExecuting; - } - [self didChangeValueForKey:@"isExecuting"]; -} - -- (BOOL)isExecuting { - std::lock_guard lock(_statusMutex); - return _executing; -} - -- (void)setFinished:(BOOL)isFinished { - if (_finished == isFinished) { - return; - } - [self willChangeValueForKey:@"isFinished"]; - { - std::lock_guard lock(_statusMutex); - _finished = isFinished; - } - [self didChangeValueForKey:@"isFinished"]; -} - -- (BOOL)isFinished { - return _finished; -} - -- (void)setConcurrent:(BOOL)isConcurrent { - if (_asynchronous == isConcurrent) { - return; - } - [self willChangeValueForKey:@"isConcurrent"]; - { - std::lock_guard lock(_statusMutex); - _asynchronous = isConcurrent; - } - [self didChangeValueForKey:@"isConcurrent"]; -} - -- (BOOL)isConcurrent { - std::lock_guard lock(_statusMutex); - return _asynchronous; -} - -- (void)setAsynchronous:(BOOL)isAsynchronous { - if (_asynchronous == isAsynchronous) { - return; - } - [self willChangeValueForKey:@"isAsynchronous"]; - { - std::lock_guard lock(_statusMutex); - _asynchronous = isAsynchronous; - } - [self didChangeValueForKey:@"isAsynchronous"]; -} - -- (BOOL)isAsynchronous { - std::lock_guard lock(_statusMutex); - return _asynchronous; -} - -- (void)setReady:(BOOL)isReady { - if (_ready == isReady) { - return; - } - [self willChangeValueForKey:@"isReady"]; - { - std::lock_guard lock(_statusMutex); - _ready = isReady; - } - [self didChangeValueForKey:@"isReady"]; -} - -- (BOOL)isReady { - std::lock_guard lock(_statusMutex); - return _ready; -} - -- (void)dealloc { - -} - -@end diff --git a/framework/ios/base/bundleoperations/HippyBundleOperationQueue.h b/framework/ios/base/bundleoperations/HippyBundleOperationQueue.h deleted file mode 100644 index b5ac962033d..00000000000 --- a/framework/ios/base/bundleoperations/HippyBundleOperationQueue.h +++ /dev/null @@ -1,33 +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 - -NS_ASSUME_NONNULL_BEGIN - -@interface HippyBundleOperationQueue : NSObject - -- (void)addOperations:(NSArray *)ops; - -@end - -NS_ASSUME_NONNULL_END diff --git a/framework/ios/base/bundleoperations/HippyBundleOperationQueue.m b/framework/ios/base/bundleoperations/HippyBundleOperationQueue.m deleted file mode 100644 index add8fe44120..00000000000 --- a/framework/ios/base/bundleoperations/HippyBundleOperationQueue.m +++ /dev/null @@ -1,87 +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 "HippyBundleOperationQueue.h" - -@interface HippyBundleOperationQueue () { - NSMutableArray *_ops; -} - -@end - -@implementation HippyBundleOperationQueue - -- (instancetype)init { - self = [super init]; - if (self) { - _ops = [NSMutableArray array]; - } - return self; -} - -- (void)addOperations:(NSArray *)ops { - if (ops) { - for (NSOperation *op in ops) { - if ([op isReady]) { - [op addObserver:self forKeyPath:@"finished" options:NSKeyValueObservingOptionNew context:NULL]; - @synchronized (self) { - [_ops addObject:op]; - } - [op start]; - } else if ([op isCancelled]) { - // do nothing - } else { - [op addObserver:self forKeyPath:@"ready" options:NSKeyValueObservingOptionNew context:NULL]; - [op addObserver:self forKeyPath:@"finished" options:NSKeyValueObservingOptionNew context:NULL]; - @synchronized (self) { - [_ops addObject:op]; - } - } - } - } -} - -- (void)observeValueForKeyPath:(NSString *)keyPath - ofObject:(id)object - change:(NSDictionary *)change - context:(void *)context { - NSNumber *value = [change objectForKey:NSKeyValueChangeNewKey]; - if (!value) { - return; - } - NSOperation *op = (NSOperation *)object; - if (![op isKindOfClass:[NSOperation class]]) { - return; - } - BOOL status = [value boolValue]; - if ([keyPath isEqualToString:@"ready"] && status) { - [op removeObserver:self forKeyPath:@"ready" context:NULL]; - [op start]; - } else if ([keyPath isEqualToString:@"finished"] && status) { - @synchronized (self) { - [_ops removeObject:object]; - } - [op removeObserver:self forKeyPath:@"finished" context:NULL]; - } -} - -@end