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!

Original source