I've been experimenting with the new Objective C JavascriptCore Framework.
This is crazy, but it seems that it doesn't have setTimeout
or setInterval
. Which... I don't understand.
I could potentially create the timer in Objective C but most of my library is written in Javascript, and aside from that, it seems just weird not having setInterval
or setTimeout
!!
I've tried a few alternative methods:
window.setInterval(function(){ /* dosomething */ }, 1000);
setInterval(function(){ /* dosomething */ }, 1000);
var interval;
interval = window.setInterval(function(){ /* dosomething */ }, 1000);
interval = setInterval(function(){ /* dosomething */ }, 1000);
I have no way to monitor what's even happening in the JSVirtualMachine either. All I know is my code stops working when there is a setInterval
called.
Any help super appreciated!
A new implementation solving an old question.
setTimout
, setInterval
and clearTimeout
are not available on the context of JavaScriptCore.
You need to implement it by yourself. I've created a swift 3 class to solve this problem. Usually, the examples show only the setTimeout
function without the option to use clearTimeout
. If you are using JS dependencies, there's a big chance that you are going to need the clearTimeout
and setInterval
functions as well.
import Foundation
import JavaScriptCore
let timerJSSharedInstance = TimerJS()
@objc protocol TimerJSExport : JSExport {
func setTimeout(_ callback : JSValue,_ ms : Double) -> String
func clearTimeout(_ identifier: String)
func setInterval(_ callback : JSValue,_ ms : Double) -> String
}
// Custom class must inherit from `NSObject`
@objc class TimerJS: NSObject, TimerJSExport {
var timers = [String: Timer]()
static func registerInto(jsContext: JSContext, forKeyedSubscript: String = "timerJS") {
jsContext.setObject(timerJSSharedInstance,
forKeyedSubscript: forKeyedSubscript as (NSCopying & NSObjectProtocol))
jsContext.evaluateScript(
"function setTimeout(callback, ms) {" +
" return timerJS.setTimeout(callback, ms)" +
"}" +
"function clearTimeout(indentifier) {" +
" timerJS.clearTimeout(indentifier)" +
"}" +
"function setInterval(callback, ms) {" +
" return timerJS.setInterval(callback, ms)" +
"}"
)
}
func clearTimeout(_ identifier: String) {
let timer = timers.removeValue(forKey: identifier)
timer?.invalidate()
}
func setInterval(_ callback: JSValue,_ ms: Double) -> String {
return createTimer(callback: callback, ms: ms, repeats: true)
}
func setTimeout(_ callback: JSValue, _ ms: Double) -> String {
return createTimer(callback: callback, ms: ms , repeats: false)
}
func createTimer(callback: JSValue, ms: Double, repeats : Bool) -> String {
let timeInterval = ms/1000.0
let uuid = NSUUID().uuidString
// make sure that we are queueing it all in the same executable queue...
// JS calls are getting lost if the queue is not specified... that's what we believe... ;)
DispatchQueue.main.async(execute: {
let timer = Timer.scheduledTimer(timeInterval: timeInterval,
target: self,
selector: #selector(self.callJsCallback),
userInfo: callback,
repeats: repeats)
self.timers[uuid] = timer
})
return uuid
}
func callJsCallback(_ timer: Timer) {
let callback = (timer.userInfo as! JSValue)
callback.call(withArguments: nil)
}
}
Usage Example:
jsContext = JSContext()
TimerJS.registerInto(jsContext: jsContext)
I hope that helps. :)