iOS: Ensure that rendering operations are serialized to prevent timing errors

This commit is contained in:
pengfei.zhou 2022-07-27 14:28:08 +08:00 committed by osborn
parent 5dd7504a37
commit 81137b8fb8
4 changed files with 62 additions and 46 deletions

View File

@ -109,7 +109,14 @@ - (id)findClass:(Class)clz target:(id)target context:(DoricContext *)context met
const char *retType = methodSignature.methodReturnType; const char *retType = methodSignature.methodReturnType;
if (!strcmp(retType, @encode(void))) { if (!strcmp(retType, @encode(void))) {
ret = nil; 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))) { } else if (!strcmp(retType, @encode(id))) {
void *retValue; void *retValue;
block(); block();

View File

@ -25,10 +25,21 @@
#import "DoricPromise.h" #import "DoricPromise.h"
#import "DoricRegistry.h" #import "DoricRegistry.h"
typedef NS_ENUM(NSUInteger, DoricThreadMode) {
DoricThreadModeUI = 1,
DoricThreadModeJS = 2,
DoricThreadModeIndependent = 3,
};
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@interface DoricNativePlugin : DoricContextHolder @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 @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END

View File

@ -23,5 +23,7 @@
#import "DoricNativePlugin.h" #import "DoricNativePlugin.h"
@implementation DoricNativePlugin @implementation DoricNativePlugin
- (DoricThreadMode)threadMode:(NSString *)method {
return DoricThreadModeIndependent;
}
@end @end

View File

@ -29,60 +29,56 @@
@implementation DoricShaderPlugin @implementation DoricShaderPlugin
- (DoricThreadMode)threadMode:(NSString *)method {
return DoricThreadModeUI;
}
- (void)render:(NSDictionary *)argument withPromise:(DoricPromise *)promise { - (void)render:(NSDictionary *)argument withPromise:(DoricPromise *)promise {
if (!argument) { if (!argument) {
return; return;
} }
[self.doricContext.performanceProfile prepare:@"Render"]; [self.doricContext.performanceProfile prepare:@"Render"];
__weak typeof(self) _self = self; if (self.doricContext == nil) {
[self.doricContext dispatchToMainQueue:^{ return;
__strong typeof(_self) self = _self; }
if (self.doricContext == nil) { [self.doricContext.performanceProfile start:@"Render"];
return; NSString *viewId = [argument optString:@"id"];
}
[self.doricContext.performanceProfile start:@"Render"];
NSString *viewId = [argument optString:@"id"];
if (self.doricContext.rootNode.viewId == nil && [@"Root" isEqualToString:[argument optString:@"type"]]) { if (self.doricContext.rootNode.viewId == nil && [@"Root" isEqualToString:[argument optString:@"type"]]) {
self.doricContext.rootNode.viewId = viewId; self.doricContext.rootNode.viewId = viewId;
[self.doricContext.rootNode blend:[argument optObject:@"props"]]; [self.doricContext.rootNode blend:[argument optObject:@"props"]];
[self.doricContext.rootNode requestLayout]; [self.doricContext.rootNode requestLayout];
} else { } else {
DoricViewNode *viewNode = [self.doricContext targetViewNode:viewId]; DoricViewNode *viewNode = [self.doricContext targetViewNode:viewId];
[viewNode blend:[argument optObject:@"props"]]; [viewNode blend:[argument optObject:@"props"]];
[viewNode requestLayout]; [viewNode requestLayout];
} }
[promise resolve:nil]; [promise resolve:nil];
[self.doricContext.performanceProfile end:@"Render"]; [self.doricContext.performanceProfile end:@"Render"];
}];
} }
- (void)command:(NSDictionary *)argument withPromise:(DoricPromise *)promise { - (void)command:(NSDictionary *)argument withPromise:(DoricPromise *)promise {
__weak typeof(self) _self = self; if (self.doricContext == nil) {
[self.doricContext dispatchToMainQueue:^{ return;
__strong typeof(_self) self = _self; }
if (self.doricContext == nil) { NSArray *viewIds = [argument optArray:@"viewIds"];
return; id args = argument[@"args"];
} NSString *name = [argument optString:@"name"];
NSArray *viewIds = [argument optArray:@"viewIds"]; DoricViewNode *viewNode = nil;
id args = argument[@"args"]; for (NSString *viewId in viewIds) {
NSString *name = [argument optString:@"name"]; if (!viewNode) {
DoricViewNode *viewNode = nil; viewNode = [self.doricContext targetViewNode:viewId];
for (NSString *viewId in viewIds) { } else {
if (!viewNode) { if ([viewNode isKindOfClass:[DoricSuperNode class]]) {
viewNode = [self.doricContext targetViewNode:viewId]; viewNode = [((DoricSuperNode *) viewNode) subNodeWithViewId:viewId];
} else {
if ([viewNode isKindOfClass:[DoricSuperNode class]]) {
viewNode = [((DoricSuperNode *) viewNode) subNodeWithViewId:viewId];
}
} }
} }
if (!viewNode) { }
[promise reject:@"Cannot find opposite view"]; if (!viewNode) {
} else { [promise reject:@"Cannot find opposite view"];
[self findClass:[viewNode class] target:viewNode method:name promise:promise argument:args]; } else {
} [self findClass:[viewNode class] target:viewNode method:name promise:promise argument:args];
}]; }
} }
- (id)createParamWithMethodName:(NSString *)method promise:(DoricPromise *)promise argument:(id)argument { - (id)createParamWithMethodName:(NSString *)method promise:(DoricPromise *)promise argument:(id)argument {