5

I am trying to execute an async function from a javascript SDK in Swift using JSCore. I have been able to accomplish evaluating and viewing the contents of the script but have been unsuccessful in actually calling the async function. Here is my code to verify I have even read the script. Any thoughts on how to accomplish this?

lazy var context: JSContext? = {
    let context = JSContext()

    guard let
        commonJSPath = Bundle.main.path(forResource: "test", ofType: "js") else {
            print("Unable to read resource files.")
            return nil
    }

    do {
        let common = try String(contentsOfFile: commonJSPath, encoding: String.Encoding.utf8)
        _ = context?.evaluateScript(common)
    } catch (let error) {
        print("Error while processing script file: \(error)")
    }

    return context
}()

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.
    setupJS()

}

func setupJS(){
    guard let context = context else {
        print("JSContext not found.")
        return
    }

    let dictionary = context.objectForKeyedSubscript("MainObject").toDictionary()
    print(dictonary)
    //let script = "const {variableName} = FooJS;";
    //let result = context.evaluateScript(script)

}

I'd like to do something like async function doSomething(){ return 'hello world!'; } console.log(await doSomething());

2
  • How do you know it hasn't been successful? Is the problem that you expect the Swift runtime to wait for some synchronous "finish" or something? Commented Oct 30, 2017 at 21:17
  • i have 2 problems, one subscripting to the actual function to call, and then awaiting the result in Swift Commented Oct 30, 2017 at 21:30

1 Answer 1

4

To call the javascript function from swift:

context.objectForKeyedSubscript("functionName_in_Javascript_file").call(withArguments: [])

In order to get control back to swift, you could define a block to be called from javascript like this:

//someString could be a result you need from javascript.

let swiftHandler: @convention(block) (String) -> Void = {(someString) in
        //do something
    }

//make block available to javasript like this:

let swiftBlock = unsafeBitCast(swiftHandler, to: AnyObject.self)

context.setObject(swiftBlock, forKeyedSubscript: "swiftCallback" as (NSCopying & NSObjectProtocol)!)

//and lastly in your javascript file, when you obtain the result you need, just call swift function using name you gave it in previous step:

swiftCallback(result);
Sign up to request clarification or add additional context in comments.

3 Comments

Does there no way to await JS functions without callbacks?
can someone give a full example for this solution? I can't seem to be able to adapt it to my scenario. Thanks
when I try to use these code snippets, I get the error about the context.setObject() line: "Value of optional type 'JSContext?' must be unwrapped to refer to member 'setObject' of wrapped base type 'JSContext'"

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.