feat:fix iOS memory leak in debugging
This commit is contained in:
@@ -23,10 +23,13 @@
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <DoricCore/Doric.h>
|
||||
#import "DoricWSClient.h"
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricDebugDriver : NSObject <DoricDriverProtocol>
|
||||
- (instancetype)initWithWSClient:(DoricWSClient *)wsClient;
|
||||
|
||||
- (void)teardown;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
@@ -57,7 +57,7 @@ - (DoricRegistry *)registry {
|
||||
- (DoricAsyncResult *)invokeDoricMethod:(NSString *)method argumentsArray:(NSArray *)args {
|
||||
DoricAsyncResult *ret = [[DoricAsyncResult alloc] init];
|
||||
__weak typeof(self) _self = self;
|
||||
[self.jsExecutor ensureRunOnJSThread:^{
|
||||
[self runInJSQueue:^{
|
||||
__strong typeof(_self) self = _self;
|
||||
if (!self) return;
|
||||
@try {
|
||||
@@ -78,7 +78,7 @@ - (DoricAsyncResult *)invokeDoricMethod:(NSString *)method argumentsArray:(NSArr
|
||||
[array addObject:arg];
|
||||
}
|
||||
__weak typeof(self) _self = self;
|
||||
[self.jsExecutor ensureRunOnJSThread:^{
|
||||
[self runInJSQueue:^{
|
||||
__strong typeof(_self) self = _self;
|
||||
if (!self) return;
|
||||
@try {
|
||||
@@ -110,7 +110,7 @@ - (DoricAsyncResult *)invokeContextEntity:(NSString *)contextId method:(NSString
|
||||
arg = va_arg(args, JSValue *);
|
||||
}
|
||||
__weak typeof(self) _self = self;
|
||||
[self.jsExecutor ensureRunOnJSThread:^{
|
||||
[self runInJSQueue:^{
|
||||
__strong typeof(_self) self = _self;
|
||||
if (!self) return;
|
||||
@try {
|
||||
@@ -132,7 +132,7 @@ - (DoricAsyncResult *)invokeContextEntity:(NSString *)contextId method:(NSString
|
||||
[array addObject:arg];
|
||||
}
|
||||
__weak typeof(self) _self = self;
|
||||
[self.jsExecutor ensureRunOnJSThread:^{
|
||||
[self runInJSQueue:^{
|
||||
__strong typeof(_self) self = _self;
|
||||
if (!self) return;
|
||||
@try {
|
||||
@@ -148,7 +148,7 @@ - (DoricAsyncResult *)invokeContextEntity:(NSString *)contextId method:(NSString
|
||||
- (DoricAsyncResult *)createContext:(NSString *)contextId script:(NSString *)script source:(NSString *)source {
|
||||
DoricAsyncResult *ret = [[DoricAsyncResult alloc] init];
|
||||
__weak typeof(self) _self = self;
|
||||
[self.jsExecutor ensureRunOnJSThread:^{
|
||||
[self runInJSQueue:^{
|
||||
__strong typeof(_self) self = _self;
|
||||
if (!self) return;
|
||||
@try {
|
||||
@@ -164,7 +164,7 @@ - (DoricAsyncResult *)createContext:(NSString *)contextId script:(NSString *)scr
|
||||
- (DoricAsyncResult *)destroyContext:(NSString *)contextId {
|
||||
DoricAsyncResult *ret = [[DoricAsyncResult alloc] init];
|
||||
NSString *theContextId = self.theContextId;
|
||||
[self.jsExecutor ensureRunOnJSThread:^{
|
||||
[self runInJSQueue:^{
|
||||
@try {
|
||||
if ([contextId isEqualToString:theContextId]) {
|
||||
[DoricDev.instance stopDebugging:NO];
|
||||
@@ -177,6 +177,12 @@ - (DoricAsyncResult *)destroyContext:(NSString *)contextId {
|
||||
return ret;
|
||||
}
|
||||
|
||||
- (void)runInJSQueue:(dispatch_block_t)block {
|
||||
[self.jsExecutor ensureRunOnJSThread:^{
|
||||
block();
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)ensureSyncInMainQueue:(dispatch_block_t)block {
|
||||
if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {
|
||||
block();
|
||||
@@ -184,4 +190,12 @@ - (void)ensureSyncInMainQueue:(dispatch_block_t)block {
|
||||
dispatch_async(dispatch_get_main_queue(), block);
|
||||
}
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self.jsExecutor teardown];
|
||||
}
|
||||
|
||||
- (void)teardown {
|
||||
[self.jsExecutor teardown];
|
||||
}
|
||||
@end
|
||||
|
@@ -42,4 +42,21 @@ - (instancetype)initWithWSClient:(DoricWSClient *)wsClient {
|
||||
- (void)initJSEngine {
|
||||
self.jsExecutor = [[DoricRemoteJSExecutor alloc] initWithWSClient:self.wsClient];
|
||||
}
|
||||
|
||||
- (void)teardown {
|
||||
[super teardown];
|
||||
if ([self.jsExecutor isKindOfClass:DoricRemoteJSExecutor.class]) {
|
||||
[((DoricRemoteJSExecutor *) (self.jsExecutor)) teardown];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)ensureRunOnJSThread:(dispatch_block_t)block {
|
||||
if ([self.jsExecutor isKindOfClass:DoricRemoteJSExecutor.class]
|
||||
&& ((DoricRemoteJSExecutor *) (self.jsExecutor)).invokingMethod) {
|
||||
NSThread *thread = [[NSThread alloc] initWithBlock:block];
|
||||
[thread start];
|
||||
} else {
|
||||
[super ensureRunOnJSThread:block];
|
||||
}
|
||||
}
|
||||
@end
|
||||
|
@@ -32,6 +32,8 @@ @interface DoricContextDebuggable : NSObject
|
||||
@property(nonatomic, weak) DoricContext *doricContext;
|
||||
@property(nonatomic, weak) id <DoricDriverProtocol> nativeDriver;
|
||||
@property(nonatomic, weak) DoricWSClient *wsClient;
|
||||
@property(nonatomic, weak) DoricDebugDriver *debugDriver;
|
||||
|
||||
@end
|
||||
|
||||
@implementation DoricContextDebuggable
|
||||
@@ -46,10 +48,12 @@ - (instancetype)initWithWSClient:(DoricWSClient *)client context:(DoricContext *
|
||||
|
||||
- (void)startDebug {
|
||||
[self.doricContext setDriver:[[DoricDebugDriver alloc] initWithWSClient:self.wsClient]];
|
||||
self.debugDriver = self.doricContext.driver;
|
||||
[self.doricContext reload:self.doricContext.script];
|
||||
}
|
||||
|
||||
- (void)stopDebug:(BOOL)resume {
|
||||
[self.debugDriver teardown];
|
||||
self.doricContext.driver = self.nativeDriver;
|
||||
if (resume) {
|
||||
[self.doricContext reload:self.doricContext.script];
|
||||
|
@@ -27,7 +27,11 @@
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface DoricRemoteJSExecutor : NSObject <DoricJSExecutorProtocol>
|
||||
@property(nonatomic, assign) BOOL invokingMethod;
|
||||
|
||||
- (instancetype)initWithWSClient:(DoricWSClient *)wsClient;
|
||||
|
||||
- (void)teardown;
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
@@ -49,8 +49,9 @@ typedef NS_ENUM(NSUInteger, DoricJSRemoteArgType) {
|
||||
@interface DoricRemoteJSExecutor () <DoricWSClientInterceptor>
|
||||
@property(nonatomic, weak) DoricWSClient *wsClient;
|
||||
@property(nonatomic, strong) NSMutableDictionary <NSString *, id> *blockMDic;
|
||||
@property(nonatomic, strong) JSValue *temp;
|
||||
@property(nonatomic, strong) dispatch_semaphore_t semaphore;
|
||||
@property(nonatomic) NSInteger counter;
|
||||
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, dispatch_semaphore_t> *semaphores;
|
||||
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, JSValue *> *results;
|
||||
@end
|
||||
|
||||
@implementation DoricRemoteJSExecutor
|
||||
@@ -59,7 +60,9 @@ - (instancetype)initWithWSClient:(DoricWSClient *)wsClient {
|
||||
_wsClient = wsClient;
|
||||
[_wsClient addInterceptor:self];
|
||||
_blockMDic = [NSMutableDictionary new];
|
||||
_semaphore = dispatch_semaphore_create(0);
|
||||
_semaphores = [NSMutableDictionary new];
|
||||
_results = [NSMutableDictionary new];
|
||||
_counter = 0;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
@@ -114,17 +117,23 @@ - (JSValue *)invokeObject:(NSString *)objName method:(NSString *)funcName args:(
|
||||
NSDictionary *dic = [self dicForArg:arg];
|
||||
[argsMArr addObject:dic];
|
||||
}
|
||||
|
||||
NSInteger callId = ++self.counter;
|
||||
[self.wsClient sendToDebugger:@"invokeMethod" payload:@{
|
||||
@"cmd": @"invokeMethod",
|
||||
@"objectName": objName,
|
||||
@"functionName": funcName,
|
||||
@"callId": @(callId),
|
||||
@"values": [argsMArr copy]
|
||||
}];
|
||||
|
||||
DC_LOCK(self.semaphore);
|
||||
|
||||
return self.temp;
|
||||
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
|
||||
self.semaphores[@(callId)] = semaphore;
|
||||
self.invokingMethod = YES;
|
||||
DoricLog(@"Lock %@",@(callId));
|
||||
DC_LOCK(semaphore);
|
||||
JSValue *result = self.results[@(callId)];
|
||||
[self.results removeObjectForKey:@(callId)];
|
||||
self.invokingMethod = NO;
|
||||
return result;
|
||||
}
|
||||
|
||||
- (NSDictionary *)dicForArg:(id)arg {
|
||||
@@ -161,32 +170,43 @@ - (BOOL)interceptType:(NSString *)type command:(NSString *)cmd payload:(NSDictio
|
||||
NSArray *argsArr = payload[@"arguments"];
|
||||
id tmpBlk = self.blockMDic[name];
|
||||
if (argsArr.count == 0) {
|
||||
((Block0) tmpBlk)();
|
||||
((Block0) tmpBlk)();
|
||||
} else if (argsArr.count == 1) {
|
||||
((Block1) tmpBlk)(argsArr[0]);
|
||||
((Block1) tmpBlk)(argsArr[0]);
|
||||
} else if (argsArr.count == 2) {
|
||||
((Block2) tmpBlk)(argsArr[0], argsArr[1]);
|
||||
((Block2) tmpBlk)(argsArr[0], argsArr[1]);
|
||||
} else if (argsArr.count == 3) {
|
||||
((Block3) tmpBlk)(argsArr[0], argsArr[1], argsArr[2]);
|
||||
((Block3) tmpBlk)(argsArr[0], argsArr[1], argsArr[2]);
|
||||
} else if (argsArr.count == 4) {
|
||||
((Block4) tmpBlk)(argsArr[0], argsArr[1], argsArr[2], argsArr[3]);
|
||||
((Block4) tmpBlk)(argsArr[0], argsArr[1], argsArr[2], argsArr[3]);
|
||||
} else if (argsArr.count == 5) {
|
||||
((Block5) tmpBlk)(argsArr[0], argsArr[1], argsArr[2], argsArr[3], argsArr[4]);
|
||||
} else {
|
||||
DoricLog(@"error:args to more than 5. args:%@", argsArr);
|
||||
}
|
||||
} else if ([cmd isEqualToString:@"invokeMethod"]) {
|
||||
NSNumber *callId = payload[@"callId"];
|
||||
@try {
|
||||
self.temp = [JSValue valueWithObject:payload[@"result"] inContext:nil];
|
||||
JSValue *value = [JSValue valueWithObject:payload[@"result"] inContext:nil];
|
||||
self.results[callId] = value;
|
||||
} @catch (NSException *exception) {
|
||||
DoricLog(@"debugger ", NSStringFromSelector(_cmd), exception.reason);
|
||||
} @finally {
|
||||
DC_UNLOCK(self.semaphore);
|
||||
DoricLog(@"Unlock:%@",payload);
|
||||
dispatch_semaphore_t semaphore = self.semaphores[callId];
|
||||
[self.semaphores removeObjectForKey:callId];
|
||||
DC_UNLOCK(semaphore);
|
||||
}
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
- (void)teardown {
|
||||
[self.blockMDic removeAllObjects];
|
||||
[self.semaphores enumerateKeysAndObjectsUsingBlock:^(NSNumber *key, dispatch_semaphore_t obj, BOOL *stop) {
|
||||
DC_UNLOCK(obj);
|
||||
}];
|
||||
}
|
||||
|
||||
@end
|
||||
|
Reference in New Issue
Block a user