Skip to content

Commit 4450f09

Browse files
Fix deadlock.
1 parent 09d44f3 commit 4450f09

4 files changed

Lines changed: 137 additions & 12 deletions

File tree

Classes/JSBScriptingSupport.m

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,12 @@
1414

1515
@import ObjectiveC;
1616

17-
static JSContext *globalContext;
18-
1917
@implementation JSBScriptingSupport
2018

21-
+ (void)initialize
19+
+ (JSContext *)globalContext
2220
{
21+
static JSContext *globalContext;
22+
2323
static dispatch_once_t onceToken;
2424
dispatch_once(&onceToken, ^{
2525
globalContext = [[JSContext alloc] init];
@@ -30,15 +30,8 @@ + (void)initialize
3030
[globalContext addScriptingSupport:@"Foundation"];
3131
[globalContext addScriptingSupport:@"UIKit"];
3232
[globalContext addScriptingSupport:@"QuartzCore"];
33-
34-
[self setupSupportFunctionsToContext:globalContext];
3533
});
36-
}
37-
38-
#pragma mark -
39-
40-
+ (JSContext *)globalContext
41-
{
34+
4235
return globalContext;
4336
}
4437

Classes/JSContext+JavaScriptBridge.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@
77
//
88

99
#import "JSContext+JavaScriptBridge.h"
10+
#import "JSBScriptingSupport+Private.h"
1011

1112
@implementation JSContext (JavaScriptBridge)
1213

1314
- (void)addScriptingSupport:(NSString *)framework
1415
{
16+
[JSBScriptingSupport setupSupportFunctionsToContext:self];
17+
1518
static NSMapTable *hashTables;
1619
if (!hashTables) {
1720
hashTables = [NSMapTable mapTableWithKeyOptions:NSPointerFunctionsWeakMemory valueOptions:NSPointerFunctionsWeakMemory];

Classes/Private/JSBScriptingSupport+Private.m

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@ + (void)setupSupportFunctionsToContext:(JSContext *)context
2727
{
2828
static NSHashTable *initializedContext;
2929
if (!initializedContext) {
30+
initializedContext = [NSHashTable hashTableWithOptions:NSPointerFunctionsWeakMemory];
31+
}
32+
if (![initializedContext containsObject:context]) {
3033
context[@"__JSB_JSBScriptingSupport"] = self;
3134
[context evaluateScript:
3235
@"JSB = (function() {\n"

Project/JavaScriptBridge/JavaScriptBridgeTests/JavaScriptBridgeTests.m

Lines changed: 127 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@
99
#import <XCTest/XCTest.h>
1010
#import "JavaScriptBridge.h"
1111

12+
@import ObjectiveC;
13+
1214
@interface JavaScriptBridgeTests : XCTestCase
1315

1416
@end
@@ -27,8 +29,132 @@ - (void)tearDown
2729

2830
- (void)testGlobalContext
2931
{
30-
JSContext *context = [JSBScriptingSupport globalContext];
32+
JSContext *globalContext = [JSBScriptingSupport globalContext];
33+
XCTAssertNotNil(globalContext);
34+
}
35+
36+
#pragma clang diagnostic push
37+
#pragma clang diagnostic ignored "-Wundeclared-selector"
38+
39+
- (void)testCustomContext
40+
{
41+
JSContext *globalContext = [JSBScriptingSupport globalContext];
42+
XCTAssertNotNil(globalContext);
43+
44+
[globalContext evaluateScript:@"var string = 'string';"];
45+
46+
JSValue *value = nil;
47+
value = globalContext[@"string"];
48+
XCTAssertTrue(value && !value.isUndefined);
49+
XCTAssertEqualObjects(value.toObject, @"string");
50+
51+
JSContext *context = [[JSContext alloc] init];
52+
context.exceptionHandler = ^(JSContext *context, JSValue *value) {
53+
NSLog(@"%@", value);
54+
};
55+
56+
[context addScriptingSupport:@"Foundation"];
57+
[context addScriptingSupport:@"UIKit"];
58+
[context addScriptingSupport:@"QuartzCore"];
59+
60+
[context evaluateScript:
61+
@"var window = UIWindow.alloc().initWithFrame(UIScreen.mainScreen().bounds);"
62+
@"window.backgroundColor = UIColor.whiteColor();"
63+
@""
64+
@"var navigationController = UINavigationController.new();"
65+
@""
66+
@"var tableViewController = UITableViewController.new();"
67+
@"tableViewController.navigationItem.title = 'JavaScriptBridge';"
68+
@"navigationController.viewControllers = [tableViewController];"
69+
@""
70+
@"var MyObject = JSB.defineClass('MyObject : NSObject', {"
71+
@" myMethod: function() {"
72+
@" return 'myMethod';"
73+
@" }"
74+
@"});"
75+
@""
76+
@"var myObject = MyObject.new();"
77+
@""
78+
@"window.rootViewController = navigationController;"
79+
];
80+
81+
XCTAssertNotNil(context);
82+
83+
value = context[@"string"];
84+
XCTAssertTrue(value && value.isUndefined);
85+
86+
value = context[@"window"];
87+
XCTAssertTrue(value && !value.isUndefined);
88+
89+
value = context[@"navigationController"];
90+
XCTAssertTrue(value && !value.isUndefined);
91+
92+
value = context[@"tableViewController"];
93+
XCTAssertTrue(value && !value.isUndefined);
94+
95+
value = context[@"myObject"];
96+
XCTAssertTrue(value && !value.isUndefined);
97+
98+
id object = value.toObject;
99+
NSString *string = [object performSelector:@selector(myMethod) withObject:nil];
100+
XCTAssertEqualObjects(string, @"myMethod");
101+
}
102+
103+
- (void)testRedefineClass
104+
{
105+
JSContext *context = [[JSContext alloc] init];
106+
context.exceptionHandler = ^(JSContext *context, JSValue *value) {
107+
NSLog(@"%@", value);
108+
};
109+
110+
[context addScriptingSupport:@"Foundation"];
111+
[context addScriptingSupport:@"UIKit"];
112+
[context addScriptingSupport:@"QuartzCore"];
113+
114+
[context evaluateScript:
115+
@"var MyObject = JSB.defineClass('MyObject : NSObject', {"
116+
@" myMethod: function() {"
117+
@" return 'myMethod';"
118+
@" }"
119+
@"});"
120+
@""
121+
@"var myObject = MyObject.new();"
122+
];
123+
31124
XCTAssertNotNil(context);
125+
126+
JSValue *value = nil;
127+
128+
value = context[@"myObject"];
129+
XCTAssertTrue(value && !value.isUndefined);
130+
131+
id object1 = value.toObject;
132+
NSString *string1 = [object1 performSelector:@selector(myMethod) withObject:nil];
133+
XCTAssertEqualObjects(string1, @"myMethod");
134+
135+
[context evaluateScript:
136+
@"var MyObject = JSB.defineClass('MyObject : NSObject', {"
137+
@" myMethod: function() {"
138+
@" return 'myMethod2';"
139+
@" },"
140+
@" anotherMethod: function() {"
141+
@" return 'anotherMethod';"
142+
@" }"
143+
@"});"
144+
@""
145+
@"var myObject = MyObject.new();"
146+
];
147+
148+
value = context[@"myObject"];
149+
XCTAssertTrue(value && !value.isUndefined);
150+
151+
id object2 = value.toObject;
152+
NSString *string2 = [object2 performSelector:@selector(myMethod) withObject:nil];
153+
XCTAssertEqualObjects(string2, @"myMethod2");
154+
155+
NSString *string3 = [object2 performSelector:@selector(anotherMethod) withObject:nil];
156+
XCTAssertEqualObjects(string3, @"anotherMethod");
32157
}
158+
#pragma clang diagnostic pop
33159

34160
@end

0 commit comments

Comments
 (0)