I'm running into some weird issues with JavaScriptCore
. Whenever I add a method to my class that has a parameter, it doesn't seem to be exported (or is exported with a weird name). For example:
import Cocoa
import JavaScriptCore
@objc
public protocol MyObjectExport: JSExport {
var property: Int { get set }
init()
func test() -> String
func doNothing(num: Int)
func squared(num: Int) -> Int
func sum(a:Int, _ b: Int) -> Int
}
@objc
public class MyObject: NSObject, MyObjectExport {
public var property: Int {
get {
return 5
}
set {
print("New value \(newValue)")
}
}
public required override init() {
}
public func test() -> String {
return "Tested"
}
public func doNothing(num: Int) {
}
public func squared(num: Int) -> Int {
return num * num
}
public func sum(a: Int, _ b: Int) -> Int {
return a + b
}
}
class ViewController: NSViewController {
override func viewDidLoad() {
let context = JSContext()!
context.exceptionHandler = { context, exc in
print("Exception \(exc)")
}
context.setObject(MyObject.self, forKeyedSubscript: NSString(string: "MyObject"))
context.evaluateScript("var obj = new MyObject()")
print(context.evaluateScript("obj"))
print(context.evaluateScript("obj.test()"))
print(context.evaluateScript("obj.doNothing(5)"))
print(context.evaluateScript("obj.squared(5)"))
print(context.evaluateScript("obj.sum(5,5)"))
}
}
Note that this has to be tested in a macOS app. JavaScriptCore acts even weirder in a playground.
When this is ran, I get the output
<TestProject.MyObject: 0x608000001180>
Tested
Exception Optional(TypeError: obj.doNothing is not a function. (In 'obj.doNothing(5)', 'obj.doNothing' is undefined))
undefined
Exception Optional(TypeError: obj.squared is not a function. (In 'obj.squared(5)', 'obj.squared' is undefined))
undefined
Exception Optional(TypeError: obj.sum is not a function. (In 'obj.sum(5,5)', 'obj.sum' is undefined))
undefined
As you can see, the initiator works and so does the method test
. However, all other methods with parameters do not seem to be exported or they are exported under some other method name I can not find.
Any help would be much appreciated.
Since Swift 3, the first parameter is no longer longer unnamed by default.
You cannot call doNothing
, squared
, and sum
from Swift code like this:
doNothing(5)
squared(5)
sum(5,5)
You must include the argument names:
doNothing(num: 5)
squared(num: 5)
sum(a: 5,5) //argument name not required for 'b' because it is '_'
Those methods get the Objective-C selectors doNothingWithNum:
, squaredWithNum:
, and sumWithA::
. These are exported to JavaScript with the following rules, according to the documentation for JSExport:
When exporting a selector that takes one or more arguments, JavaScriptCore generates a corresponding function name using the following conversion:
All colons are removed from the selector.
Any lowercase letter that had followed a colon is capitalized.
So doNothing
, squared
, and sum
are called doNothingWithNum()
, squaredWithNum()
, and sumWithA()
. You have to either change your JavaScript to call the methods with those names:
print(context.evaluateScript("obj.doNothingWithNum(5)"))
print(context.evaluateScript("obj.squaredWithNum(5)"))
print(context.evaluateScript("obj.sumWithA(5,5)"))
Or change your class & protocol definitions to remove the parameter names:
@objc
public protocol MyObjectExport: JSExport {
var property: Int { get set }
init()
func test() -> String
func doNothing(_ num: Int)
func squared(_ num: Int) -> Int
func sum(_ a: Int, _ b: Int) -> Int
}
@objc
public class MyObject: NSObject, MyObjectExport {
public var property: Int {
get {
return 5
}
set {
print("New value \(newValue)")
}
}
public required override init() {
}
public func test() -> String {
return "Tested"
}
public func doNothing(_ num: Int) {
}
public func squared(_ num: Int) -> Int {
return num * num
}
public func sum(_ a: Int, _ b: Int) -> Int {
return a + b
}
}