Skip to content

Instantly share code, notes, and snippets.

@MarkVillacampa
Last active December 27, 2015 19:49
Show Gist options
  • Save MarkVillacampa/7379799 to your computer and use it in GitHub Desktop.
Save MarkVillacampa/7379799 to your computer and use it in GitHub Desktop.
Trying to add methods at runtime for the JSExport protocol in JavaScriptCore. As-is, the method is not called from Javascript. Uncomment lines 7-8 and the end of 11, comment line 65, and run. The method is now called from JavaSript. Any idea why?
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
#import <objc/runtime.h>
const char *_protocol_getMethodTypeEncoding(Protocol *, SEL, BOOL isRequiredMethod, BOOL isInstanceMethod);
//@protocol MyProtocol <JSExport>
// -(void)one:(id)one;
//@end
@interface MyClass : NSObject //<MyProtocol>
-(void)one:(id)one;
+(Protocol*)getProtocol:(NSString*)protocol;
+(void)addProtocol:(NSString*)protocol extendingProtocol:(NSString*)extends withMethods:(NSArray*)methods;
@end
@implementation MyClass : NSObject
-(void)one:(id)one
{
NSLog(@"Hello!");
}
+(void)addProtocol:(NSString*)protocol extendingProtocol:(NSString*)extends withMethods:(NSArray*)methods;
{
Protocol *prot = [self getProtocol:protocol];
if (extends != nil)
{
protocol_addProtocol(prot, objc_getProtocol([extends UTF8String]));
}
if (methods != nil)
{
for(NSString *method in methods)
{
bool instance = true;
Method m = class_getInstanceMethod(self, NSSelectorFromString(method));
if (m == nil)
{
instance = false;
m = class_getClassMethod(self, NSSelectorFromString(method));
}
const char *types = method_getTypeEncoding(m);
protocol_addMethodDescription(prot, NSSelectorFromString(method), types, true, instance);
}
}
objc_registerProtocol(prot);
class_addProtocol([self class], prot);
}
+(Protocol*)getProtocol:(NSString*)protocol
{
Protocol *prot = objc_getProtocol([protocol UTF8String]);
if (prot == nil)
{
prot = objc_allocateProtocol([protocol UTF8String]);
}
return prot;
}
@end
int main(int argc, char *argv[]) {
@autoreleasepool {
@protocol(JSExport); // Stub needed to "see" the protocol at runtime.
[MyClass addProtocol:@"MyProtocol" extendingProtocol:@"JSExport" withMethods: @[@"one:"]];
JSContext *context = JSContext.new;
// MyClass *myclass = MyClass.class;
// context[@"Myclass"] = myclass;
// [context evaluateScript:@"Myclass.one()"];
NSLog(@"Conforms to JSExport: %d", class_conformsToProtocol(NSClassFromString(@"MyClass"), objc_getProtocol([@"JSExport" UTF8String])));
NSLog(@"Conforms to MyProtocol: %d", class_conformsToProtocol(NSClassFromString(@"MyClass"), objc_getProtocol([@"MyProtocol" UTF8String])));
uint *outCount;
protocol_copyMethodDescriptionList(objc_getProtocol([@"MyProtocol" UTF8String]), true, true, &outCount);
protocol_copyMethodDescriptionList(objc_getProtocol([@"MyProtocol" UTF8String]), true, true, &outCount);
NSLog(@"Types: %s", protocol_getMethodDescription(NSProtocolFromString(@"MyProtocol"),NSSelectorFromString(@"one:"), true, true).types);
NSLog(@"Types internal: %s", _protocol_getMethodTypeEncoding(NSProtocolFromString(@"MyProtocol"),NSSelectorFromString(@"one:"), true, true));
NSLog(@"Number of methods in MyProtocol: %i", outCount);
}
}
@sdegutis
Copy link

fwiw this is one of the biggest reasons I ditched JS and went with Lua for my app's extension stuff

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment