Patching console.log into Swift's JavaScriptCore JSContext
By default, you cannot print to the Xcode console from within a JavaScriptCore-evaluated script. print
, echo
, console.log
– nothing of the like is available.
Caveman debugging is tremendously useful, though, so we all know that we want to print from the JavaScript we evaluat, right?
With my subscript extensions, you can patch this into your JSContext
in a rather simple manner.
Note that the usual console.log("hello!")
call is a method call (log
) on the console
object. Without my subscript extensions, you’d have to use the objectForKeyedSubscript
getter on the JSContext
first to get to the console
object, and then use setObject(_:forKeyedSubscript:)
on the JSValue
to add a block that prints a String. With the extension, we can write this instead:
let logHandler: @convention(block) (String) -> Void = { string in
print(string)
}
jsContext["console"]?["log"] = logHandler
We still have to add the @convention(block)
annotation, though. Without it, the logHandler
would be passed in as an NSObject
reference – but these cannot be called like a regular function can, so that won’t help.
I think this subscript stuff is quite useful. Reduces the noise tremendously.
Please keep in mind that the actual console.log
API documentation clearly states that you can pass more than mere strings to this method. It supports variadic arguments for formatted strings, and it supports printing objects. I leave this as an exercise for the reader, heh.