Using setInterval, setTimeout in JavascriptCore Framework for ObjectiveC
ios7, javascript, javascriptcore, objective-c
Solution
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. :)
Problem
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. - Am I right about this? - Are there alternatives? 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!