From 81137b8fb894df8125a5c509b79b0b08636c0e1d Mon Sep 17 00:00:00 2001 From: "pengfei.zhou" Date: Wed, 27 Jul 2022 14:28:08 +0800 Subject: [PATCH] iOS: Ensure that rendering operations are serialized to prevent timing errors --- .../Classes/Extension/DoricBridgeExtension.m | 9 +- .../Pod/Classes/Plugin/DoricNativePlugin.h | 13 ++- .../Pod/Classes/Plugin/DoricNativePlugin.m | 4 +- .../Pod/Classes/Plugin/DoricShaderPlugin.m | 82 +++++++++---------- 4 files changed, 62 insertions(+), 46 deletions(-) diff --git a/doric-iOS/Pod/Classes/Extension/DoricBridgeExtension.m b/doric-iOS/Pod/Classes/Extension/DoricBridgeExtension.m index 99935b38..edf8f273 100644 --- a/doric-iOS/Pod/Classes/Extension/DoricBridgeExtension.m +++ b/doric-iOS/Pod/Classes/Extension/DoricBridgeExtension.m @@ -109,7 +109,14 @@ - (id)findClass:(Class)clz target:(id)target context:(DoricContext *)context met const char *retType = methodSignature.methodReturnType; if (!strcmp(retType, @encode(void))) { ret = nil; - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block); + DoricThreadMode mode = [target threadMode:methodName]; + if (mode == DoricThreadModeUI) { + dispatch_async(dispatch_get_main_queue(), block); + } else if (mode == DoricThreadModeJS) { + block(); + } else { + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block); + } } else if (!strcmp(retType, @encode(id))) { void *retValue; block(); diff --git a/doric-iOS/Pod/Classes/Plugin/DoricNativePlugin.h b/doric-iOS/Pod/Classes/Plugin/DoricNativePlugin.h index 0616dfc0..9fdb4b6f 100644 --- a/doric-iOS/Pod/Classes/Plugin/DoricNativePlugin.h +++ b/doric-iOS/Pod/Classes/Plugin/DoricNativePlugin.h @@ -25,10 +25,21 @@ #import "DoricPromise.h" #import "DoricRegistry.h" +typedef NS_ENUM(NSUInteger, DoricThreadMode) { + DoricThreadModeUI = 1, + DoricThreadModeJS = 2, + DoricThreadModeIndependent = 3, +}; + NS_ASSUME_NONNULL_BEGIN @interface DoricNativePlugin : DoricContextHolder - +/** + * Determines which thread this method should run on + * @param method name of method + * @return thread where this method should run on,default is DoricThreadModeIndependent + * */ +- (DoricThreadMode)threadMode:(NSString *)method; @end NS_ASSUME_NONNULL_END diff --git a/doric-iOS/Pod/Classes/Plugin/DoricNativePlugin.m b/doric-iOS/Pod/Classes/Plugin/DoricNativePlugin.m index 6e1bc8e5..9242d5e1 100644 --- a/doric-iOS/Pod/Classes/Plugin/DoricNativePlugin.m +++ b/doric-iOS/Pod/Classes/Plugin/DoricNativePlugin.m @@ -23,5 +23,7 @@ #import "DoricNativePlugin.h" @implementation DoricNativePlugin - +- (DoricThreadMode)threadMode:(NSString *)method { + return DoricThreadModeIndependent; +} @end diff --git a/doric-iOS/Pod/Classes/Plugin/DoricShaderPlugin.m b/doric-iOS/Pod/Classes/Plugin/DoricShaderPlugin.m index 6adcdedd..df9c907b 100644 --- a/doric-iOS/Pod/Classes/Plugin/DoricShaderPlugin.m +++ b/doric-iOS/Pod/Classes/Plugin/DoricShaderPlugin.m @@ -29,60 +29,56 @@ @implementation DoricShaderPlugin +- (DoricThreadMode)threadMode:(NSString *)method { + return DoricThreadModeUI; +} + - (void)render:(NSDictionary *)argument withPromise:(DoricPromise *)promise { if (!argument) { return; } [self.doricContext.performanceProfile prepare:@"Render"]; - __weak typeof(self) _self = self; - [self.doricContext dispatchToMainQueue:^{ - __strong typeof(_self) self = _self; - if (self.doricContext == nil) { - return; - } - [self.doricContext.performanceProfile start:@"Render"]; - NSString *viewId = [argument optString:@"id"]; + if (self.doricContext == nil) { + return; + } + [self.doricContext.performanceProfile start:@"Render"]; + NSString *viewId = [argument optString:@"id"]; - if (self.doricContext.rootNode.viewId == nil && [@"Root" isEqualToString:[argument optString:@"type"]]) { - self.doricContext.rootNode.viewId = viewId; - [self.doricContext.rootNode blend:[argument optObject:@"props"]]; - [self.doricContext.rootNode requestLayout]; - } else { - DoricViewNode *viewNode = [self.doricContext targetViewNode:viewId]; - [viewNode blend:[argument optObject:@"props"]]; - [viewNode requestLayout]; - } - [promise resolve:nil]; - [self.doricContext.performanceProfile end:@"Render"]; - }]; + if (self.doricContext.rootNode.viewId == nil && [@"Root" isEqualToString:[argument optString:@"type"]]) { + self.doricContext.rootNode.viewId = viewId; + [self.doricContext.rootNode blend:[argument optObject:@"props"]]; + [self.doricContext.rootNode requestLayout]; + } else { + DoricViewNode *viewNode = [self.doricContext targetViewNode:viewId]; + [viewNode blend:[argument optObject:@"props"]]; + [viewNode requestLayout]; + } + [promise resolve:nil]; + [self.doricContext.performanceProfile end:@"Render"]; } - (void)command:(NSDictionary *)argument withPromise:(DoricPromise *)promise { - __weak typeof(self) _self = self; - [self.doricContext dispatchToMainQueue:^{ - __strong typeof(_self) self = _self; - if (self.doricContext == nil) { - return; - } - NSArray *viewIds = [argument optArray:@"viewIds"]; - id args = argument[@"args"]; - NSString *name = [argument optString:@"name"]; - DoricViewNode *viewNode = nil; - for (NSString *viewId in viewIds) { - if (!viewNode) { - viewNode = [self.doricContext targetViewNode:viewId]; - } else { - if ([viewNode isKindOfClass:[DoricSuperNode class]]) { - viewNode = [((DoricSuperNode *) viewNode) subNodeWithViewId:viewId]; - } + if (self.doricContext == nil) { + return; + } + NSArray *viewIds = [argument optArray:@"viewIds"]; + id args = argument[@"args"]; + NSString *name = [argument optString:@"name"]; + DoricViewNode *viewNode = nil; + for (NSString *viewId in viewIds) { + if (!viewNode) { + viewNode = [self.doricContext targetViewNode:viewId]; + } else { + if ([viewNode isKindOfClass:[DoricSuperNode class]]) { + viewNode = [((DoricSuperNode *) viewNode) subNodeWithViewId:viewId]; } } - if (!viewNode) { - [promise reject:@"Cannot find opposite view"]; - } else { - [self findClass:[viewNode class] target:viewNode method:name promise:promise argument:args]; - } - }]; + } + if (!viewNode) { + [promise reject:@"Cannot find opposite view"]; + } else { + [self findClass:[viewNode class] target:viewNode method:name promise:promise argument:args]; + } } - (id)createParamWithMethodName:(NSString *)method promise:(DoricPromise *)promise argument:(id)argument {