Skip to content

Commit e4032b2

Browse files
Support to define static methods.
1 parent 09b4fe5 commit e4032b2

5 files changed

Lines changed: 197 additions & 145 deletions

File tree

Classes/JSBScriptingSupport.m

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
#import "JSBScriptingSupport.h"
1010
#import "JSBNSObject.h"
1111
#import "JSBMessageForwarding.h"
12-
#import "UIControl+JavaScriptBridge.h"
1312
#import "JSContext+JavaScriptBridge.h"
1413

1514
@import ObjectiveC;
@@ -106,29 +105,36 @@ + (id)defineClass:(NSString *)declaration instanceMembers:(JSValue *)instanceMem
106105

107106
Class superClass = class_getSuperclass(cls);
108107
if (superClass) {
109-
setupForwardingImplementations(cls, superClass, instanceMembers);
108+
setupForwardingImplementations(cls, superClass, instanceMembers, staticMembers);
110109
}
111110

112111
NSString *types;
113112
BOOL result;
114113

114+
Class metaClass = objc_getMetaClass(className.UTF8String);
115+
115116
types = [NSString stringWithFormat: @"%s%s%s%s", @encode(NSMethodSignature), @encode(id), @encode(SEL), @encode(SEL)];
116117
result = class_addMethod(cls, @selector(methodSignatureForSelector:), (IMP)methodSignatureForSelector, types.UTF8String);
118+
result = class_addMethod(metaClass, @selector(methodSignatureForSelector:), (IMP)methodSignatureForSelector, types.UTF8String);
117119

118120
types = [NSString stringWithFormat: @"%s%s%s%s", @encode(void), @encode(id), @encode(SEL), @encode(NSInvocation)];
119121
result = class_addMethod(cls, @selector(forwardInvocation:), (IMP)forwardInvocation, types.UTF8String);
122+
result = class_addMethod(metaClass, @selector(forwardInvocation:), (IMP)forwardInvocation, types.UTF8String);
120123

121124
types = [NSString stringWithFormat: @"%s%s%s%s", @encode(BOOL), @encode(id), @encode(SEL), @encode(SEL)];
122125
result = class_addMethod(cls, @selector(respondsToSelector:), (IMP)respondsToSelector, types.UTF8String);
126+
result = class_addMethod(metaClass, @selector(respondsToSelector:), (IMP)respondsToSelector, types.UTF8String);
123127

124128
for (NSString *protocol in [protocols componentsSeparatedByString:@","]) {
125129
class_addProtocol(cls, NSProtocolFromString([protocol stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]]));
126130
}
127131

128132
class_addProtocol(cls, @protocol(JSBNSObject));
129133

130-
globalContext[mangledNameFromClass(cls)] = cls;
131-
globalContext[mangledNameFromClass(cls)][@"instanceMembers"] = instanceMembers;
134+
NSString *key = mangledNameFromClass(cls);
135+
globalContext[key] = cls;
136+
globalContext[key][JSBInstanceMembersKey] = instanceMembers;
137+
globalContext[key][JSBStaticMembersKey] = staticMembers;
132138

133139
return cls;
134140
}

Classes/Private/JSBMessageForwarding.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
#import <Foundation/Foundation.h>
1010

11+
extern NSString * const JSBInstanceMembersKey;
12+
extern NSString * const JSBStaticMembersKey;
13+
1114
@import JavaScriptCore;
1215

1316
NSString *mangledNameFromClass(Class cls);
@@ -24,7 +27,7 @@ CGFloat tableViewHeightForRowAtIndexPath(id self, SEL _cmd, UITableView *tableVi
2427
CGFloat tableViewHeightForHeaderInSection(id self, SEL _cmd, UITableView *tableView, NSInteger section);
2528
CGFloat tableViewHeightForFooterInSection(id self, SEL _cmd, UITableView *tableView, NSInteger section);
2629

27-
void setupForwardingImplementations(Class targetClass, Class cls, JSValue *functions);
30+
void setupForwardingImplementations(Class targetClass, Class cls, JSValue *instanceFunctions, JSValue *staticFunctions);
2831

2932
void forwardInvocation(id self, SEL _cmd, NSInvocation *invocation);
3033
NSMethodSignature *methodSignatureForSelector(id self, SEL _cmd, SEL selector);

Classes/Private/JSBMessageForwarding.m

Lines changed: 64 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
#import "JSBMessageForwarding.h"
1010
#import "JSBScriptingSupport.h"
1111

12+
NSString * const JSBInstanceMembersKey = @"instanceMembers";
13+
NSString * const JSBStaticMembersKey = @"staticMembers";
14+
1215
@import JavaScriptCore;
1316
@import ObjectiveC;
1417

@@ -36,6 +39,22 @@
3639
return propertyName;
3740
}
3841

42+
JSValue *propertyForObject(id obj, NSString *propertyName)
43+
{
44+
JSContext *context = [JSBScriptingSupport globalContext];
45+
46+
JSValue *properties = nil;
47+
48+
Class cls = object_getClass(obj);
49+
if (class_isMetaClass(cls)) {
50+
properties = context[mangledNameFromClass(obj)][JSBStaticMembersKey];
51+
} else {
52+
properties = context[mangledNameFromClass(cls)][JSBInstanceMembersKey];
53+
}
54+
55+
return properties[propertyName];
56+
}
57+
3958
#pragma mark -
4059

4160
void invokeSuper(NSInvocation *inv)
@@ -196,7 +215,7 @@ CGFloat tableViewHeightForRowAtIndexPath(id self, SEL _cmd, UITableView *tableVi
196215
JSContext *context = [JSBScriptingSupport globalContext];
197216

198217
NSString *propertyName = propertyNameFromSelector(_cmd);
199-
JSValue *function = context[mangledNameFromClass([self class])][@"instanceMembers"][propertyName];
218+
JSValue *function = context[mangledNameFromClass(object_getClass(self))][JSBInstanceMembersKey][propertyName];
200219

201220
if (!function.isUndefined) {
202221
JSValue *returnValue = [function callWithArguments:@[tableView, indexPath]];
@@ -211,7 +230,7 @@ CGFloat tableViewHeightForHeaderInSection(id self, SEL _cmd, UITableView *tableV
211230
JSContext *context = [JSBScriptingSupport globalContext];
212231

213232
NSString *propertyName = propertyNameFromSelector(_cmd);
214-
JSValue *function = context[mangledNameFromClass([self class])][@"instanceMembers"][propertyName];
233+
JSValue *function = context[mangledNameFromClass(object_getClass(self))][JSBInstanceMembersKey][propertyName];
215234

216235
if (!function.isUndefined) {
217236
JSValue *returnValue = [function callWithArguments:@[tableView, @(section)]];
@@ -226,7 +245,7 @@ CGFloat tableViewHeightForFooterInSection(id self, SEL _cmd, UITableView *tableV
226245
JSContext *context = [JSBScriptingSupport globalContext];
227246

228247
NSString *propertyName = propertyNameFromSelector(_cmd);
229-
JSValue *function = context[mangledNameFromClass([self class])][@"instanceMembers"][propertyName];
248+
JSValue *function = context[mangledNameFromClass(object_getClass(self))][JSBInstanceMembersKey][propertyName];
230249

231250
if (!function.isUndefined) {
232251
JSValue *returnValue = [function callWithArguments:@[tableView, @(section)]];
@@ -238,16 +257,16 @@ CGFloat tableViewHeightForFooterInSection(id self, SEL _cmd, UITableView *tableV
238257

239258
#pragma mark -
240259

241-
void setupForwardingImplementations(Class targetClass, Class cls, JSValue *functions)
260+
void setupForwardingImplementations(Class targetClass, Class cls, JSValue *instanceFunctions, JSValue *staticFunctions)
242261
{
243-
unsigned int count = 0;
244-
Method *methods = class_copyMethodList(cls, &count);
245-
for (unsigned int i = 0; i < count; i++) {
246-
Method m = methods[i];
247-
struct objc_method_description *description = method_getDescription(m);
262+
unsigned int numberOfInstanceMethods = 0;
263+
Method *instanceMethods = class_copyMethodList(cls, &numberOfInstanceMethods);
264+
for (unsigned int i = 0; i < numberOfInstanceMethods; i++) {
265+
Method method = instanceMethods[i];
266+
struct objc_method_description *description = method_getDescription(method);
248267

249268
NSString *propertyName = propertyNameFromSelector(description->name);
250-
JSValue *function = functions[propertyName];
269+
JSValue *function = instanceFunctions[propertyName];
251270
if (!function.isUndefined) {
252271
if (strcmp(@encode(NSInteger), "q") == 0) { // for 64bit devices
253272
if (description->name == @selector(tableView:heightForRowAtIndexPath:)) {
@@ -274,13 +293,31 @@ void setupForwardingImplementations(Class targetClass, Class cls, JSValue *funct
274293
class_addMethod(targetClass, description->name, _objc_msgForward, description->types);
275294
}
276295
}
277-
if (methods) {
278-
free(methods);
296+
if (instanceMethods) {
297+
free(instanceMethods);
298+
}
299+
300+
unsigned int numberOfClassMethods = 0;
301+
Class metaClass = objc_getMetaClass(class_getName(cls));
302+
Class targetMetaClass = objc_getMetaClass(class_getName(targetClass));
303+
Method *classMethods = class_copyMethodList(metaClass, &numberOfClassMethods);
304+
for (unsigned int i = 0; i < numberOfClassMethods; i++) {
305+
Method method = classMethods[i];
306+
struct objc_method_description *description = method_getDescription(method);
307+
308+
NSString *propertyName = propertyNameFromSelector(description->name);
309+
JSValue *function = staticFunctions[propertyName];
310+
if (!function.isUndefined) {
311+
class_addMethod(targetMetaClass, description->name, _objc_msgForward, description->types);
312+
}
313+
}
314+
if (classMethods) {
315+
free(classMethods);
279316
}
280317

281318
Class superClass = class_getSuperclass(cls);
282319
if (superClass) {
283-
setupForwardingImplementations(targetClass, superClass, functions);
320+
setupForwardingImplementations(targetClass, superClass, instanceFunctions, staticFunctions);
284321
}
285322
}
286323

@@ -298,7 +335,7 @@ void forwardInvocation(id self, SEL _cmd, NSInvocation *invocation)
298335
context[@"self"] = self;
299336

300337
NSString *propertyName = propertyNameFromSelector(invocation.selector);
301-
JSValue *function = context[mangledNameFromClass([self class])][@"instanceMembers"][propertyName];
338+
JSValue *function = propertyForObject(self, propertyName);
302339

303340
if (!function.isUndefined) {
304341
NSArray *arguments = extractArguments(invocation);
@@ -313,11 +350,18 @@ void forwardInvocation(id self, SEL _cmd, NSInvocation *invocation)
313350
NSMethodSignature *methodSignatureForSelector(id self, SEL _cmd, SEL selector)
314351
{
315352
NSMethodSignature *methodSignature = nil;
353+
Class cls = object_getClass(self);
316354

317-
Class cls = [self class];
318-
methodSignature = [cls instanceMethodSignatureForSelector:selector];
319-
if (methodSignature) {
320-
return methodSignature;
355+
if (class_isMetaClass(cls)) {
356+
methodSignature = [cls instanceMethodSignatureForSelector:selector];
357+
if (methodSignature) {
358+
return methodSignature;
359+
}
360+
} else {
361+
methodSignature = [cls instanceMethodSignatureForSelector:selector];
362+
if (methodSignature) {
363+
return methodSignature;
364+
}
321365
}
322366

323367
NSUInteger numberOfArguments = [[NSStringFromSelector(selector) componentsSeparatedByString:@":"] count] - 1;
@@ -326,10 +370,8 @@ void forwardInvocation(id self, SEL _cmd, NSInvocation *invocation)
326370

327371
BOOL respondsToSelector(id self, SEL _cmd, SEL selector)
328372
{
329-
JSContext *context = [JSBScriptingSupport globalContext];
330-
331373
NSString *propertyName = propertyNameFromSelector(selector);
332-
JSValue *value = context[mangledNameFromClass([self class])][@"instanceMembers"][propertyName];
374+
JSValue *function = propertyForObject(self, propertyName);
333375

334-
return !value.isUndefined;
376+
return !function.isUndefined;
335377
}

Examples/HelloWorld/HelloWorld.xcodeproj/project.pbxproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,6 +797,7 @@
797797
14A0452A18782920004831E8 /* Products */,
798798
);
799799
sourceTree = "<group>";
800+
wrapsLines = 0;
800801
};
801802
14A0452A18782920004831E8 /* Products */ = {
802803
isa = PBXGroup;

0 commit comments

Comments
 (0)