2

I'm trying to use native Swift code in javacript that runs in a JSContext.

For example I have this class implemented in Swift:

class Greeter: NSObject {

   public func greet() -> String {
     return "Hello World!"
   }

   public func greetMe(_ name: String) -> String {
     return "Hello, " + name + "!"
   }
}

Then I use a JSContext to run a javascript code:

let context =  JSContext()!
context.setObject(Greeter.self, forKeyedSubscript: "Greeter" as (NSCopying & NSObjectProtocol))

// Try my native functions:
let jsv1 = context.evaluateScript("Greeter.greet()")!
let jsv2 = context.evaluateScript("Greeter.greetMe(\"Jon Arbuckle\")")!

print("Greeter.greet() =  \(jsv1)") // prints Greeter.greet() = undefined
print("Greeter.greatMe(\"Jon Arbuckle\") = \(jsv2)") // prints Greeter.greetMe("Jon Arbuckle") = undefined

Couldn't figure out what I'm doing wrong.

1 Answer 1

5

One thing we should not forget is to expose methods or properties by conforming to JSExport protocol.

@objc protocol GreeterJSExports: JSExport {
   func greet() -> String
   func greetMe(_ name: String) -> String
   static func getInstance() -> Greeter
   //any other properties you may want to export to JS runtime 
   //var greetings: String {get set}
}

Conform to this protocol

class Greeter: NSObject, GreeterJSExports {
   public func greet() -> String {
     return "Hello World!"
   }

   public func greetMe(_ name: String) -> String {
     return "Hello, " + name + "!"
   }
   class func getInstance() -> Greeter {
     return Greeter()
   }
}

Set the object in JSContext as usual

let context = JSContext()
context?.setObject(Greeter.self, forKeyedSubscript: "Greeter" as (NSCopying & NSObjectProtocol))
let jsValue1 = context?.evaluateScript("(function(){ var greeter = Greeter.getInstance(); return greeter.greet()})()")
let jsValue2 = context?.evaluateScript("(function(){ var greeter = Greeter.getInstance(); return greeter.greetMe('rikesh')})()")
print(jsValue1!)
print(jsValue2!)

Remember, the above methods are instance methods. We need object to call it. Swift does not expose init(), hence, I added a method to getInstance to return an instance.

Sign up to request clarification or add additional context in comments.

2 Comments

your answer sadly did not solve my problem. I uploaded a screenshot of my Swift playground. I'm using Xcode 9.4.1.
It's not working in a Playground but works in an actual project. Here's the screenshot imgur.com/a/VkbjEVz

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.