NFI Swift - JavaScript API Reference
Creating Objects
var obj = new MyClass(); // standard init
var obj = new MyClass("hello", 42); // parameterised init
var obj = MyClass.jsnew("abc"); // use for failable init? — returns null on failure
Calling Methods
obj.methodName(arg1, arg2);
Swift argument labels are not preserved. Pass arguments positionally, following the order in which they are declared.
// Swift: func move(to point: Point, duration: Double) -> Bool
// JS: obj.move(point, 1.5);
Properties
// Read var val = obj.propertyName; // Write obj.propertyName = newValue;
Assignments to read-only properties (Swift { get }) are silently ignored.
Static Methods and Properties
var result = MyClass.staticMethod(arg); var val = MyClass.staticProperty; MyClass.staticProperty = newValue;
Singletons
var shared = MyClass.shared; // access the shared instance shared.doSomething();
Method Chaining
Methods that return Self are supported naturally.
var result = builder.select("*").from("users").where("age > 18").limit(5).build();
Subscripts
obj["key"] // String-keyed subscript get obj["key"] = v // String-keyed subscript set (if read-write) obj[0] // Int-keyed subscript get
Type Mapping
| Swift Type | JavaScript Value |
|---|---|
| Int, Int32, UInt, Int64 | number |
| Double, Float, CGFloat | number |
| Bool | boolean |
| String | string |
| Character | single-character string |
| Data | Array of byte numbers [202, 254, …] |
| URL | string (the URL's absolute string) |
| Date | number (milliseconds since epoch) |
| Error | string (localised description) or an enum ref |
| [T] (Array) | JS Array |
| [K:V] (Dictionary) | JS Object / dict |
| Set<T> | JS Array (order not guaranteed) |
| Optional<T> — .none | null |
| Named tuple (a: T, b: U) | JS Object { a: …, b: … } |
| Class instance | Wrapped JS object with prototype methods |
| Struct instance | Wrapped JS object with prototype methods |
| UIColor | [r, g, b, a] (Doubles 0.0–1.0) |
| CGRect | { x, y, width, height } |
| CGPoint | { x, y } |
| CGSize | { width, height } |
Supported Swift Features
Primitives and Strings
The following Swift types are supported as parameter and return types: Int, Int32, UInt, Double, Float, CGFloat), Bool, String, Character, Data, URL, Date, and Error.
Optionals
Optional variants of all supported types are also supported. nil is mapped to null in JavaScript, and null can be passed from JavaScript for optional parameters.
Collections
[String], [Int], [Double], [Bool], [Data], [URL], [String:Any], Set<String>, nested arrays, and nested dictionaries.
Classes and Inheritance
Single and multi-level class inheritance. Subclass instances retain access to all superclass methods.
Structs
Structs with stored properties and instance methods. Properties are read/write from JS.
Enums
| Pattern | Supported |
|---|---|
| Raw-value enum (String, Int) | obj.rawValue, MyEnum.init_rawValue("val") |
| Instance methods on enum cases | obj.methodName() |
| Associated-value enum | describe() and label computed property |
Closures and Callbacks
Closures as method parameters, including completion handlers:
// Swift
func compute(_ a: Int, _ b: Int, using op: (Int, Int) -> Int) -> Int
// JS
var result = obj.compute(10, 5, function(a, b) { return a + b; });
Completion handlers (async callbacks):
// Swift
func fetchData(completion: (String?, Error?) -> Void)
// JS
obj.fetchData(function(value, error) {
if (error) { /* handle */ }
kony.print(value);
});
Async / Concurrency
async methods are supported via a completion-handler bridge pattern. The result is delivered to a JS callback; the synchronous return from JS will be null.
// Sync return is null — use the callback
obj.fetchMessage(function(result, err) {
kony.print("result:", result);
});
Throwing Methods
Swift throws is bridged via a Result-style callback or by checking the returned error:
var val = obj.parsePositive(5); // returns value on success var val = obj.parsePositive(-1); // returns null; error accessible if needed
Protocols and Protocol Conformance
Classes conforming to protocols expose all protocol methods. Methods provided by protocol extensions (default implementations) are also available.
var g = new Greeter("Alice");
g.greet(); // own method
g.farewell(); // from protocol extension default
Method Overloading
Overloads with different parameter counts are dispatched correctly. Overloads that differ only by Int vs Double (same arity) fall back to Int (known limitation).
Static Factory Methods
var v = Vehicle.create("Tesla", 2023, "Electric", 320);
var g = Person.guest();
Named Tuple Returns
Named tuples are returned as JS dictionaries:
var stats = s.analyze([1, 2, 3, 4, 5]); kony.print(stats.min, stats.max, stats.average, stats.count); var parts = s.partition([1,5,3,8,2], 5); kony.print(parts.below); // array of values < 5 kony.print(parts.above); // array of values >= 5
Computed Properties
Computed get-only and get/set properties on classes and structs are accessible as regular JS properties.
inout Parameters
Void methods with inout parameters return a JS dict of all mutated values keyed by the Swift parameter name:
// Swift public func swap(_ a: inout Int, _ b: inout Int) public func clamp(_ value: inout Double, lo: Double, hi: Double) var result = helper.swap(3, 7); kony.print(result.a); // 7 kony.print(result.b); // 3 var c = helper.clamp(15.0, 0.0, 10.0); kony.print(c.value); // 10
Non-void inout methods return their explicit return value as normal (the Swift return value, not a dict).
willSet / didSet Property Observers
Property observers fire on the Swift side automatically when the property is set via JS. Read the side-effect properties back after the assignment:
store.value = 10; kony.print(store.changeCount); // 1 (incremented by willSet) kony.print(store.lastValue); // 0 (captured by didSet)
Type Aliases
typealias declarations in Swift source are fully resolved by the tool. Use type aliases exactly as you would the underlying type — aliases for closures, dicts, arrays, and named tuples all work transparently:
// Swift
public typealias IntMapper = (Int) -> Int
public typealias JSONDict = [String: Any]
var result = demo.transform([1, 2, 3, 4], function(n) { return n * 2; });
var info = demo.describe("score", 99); // { key: "score", value: 99, type: "int" }
@discardableResult
Swift methods marked @discardableResult are dispatched normally, and their return values remain available in JS whether used or discarded:
var count = logger.log("event"); // use the return value
logger.log("event"); // discard it — both work
Protocol as Method Parameter Type
Pass any wrapped instance whose Swift class conforms to the protocol — no special JS syntax required:
// Swift public func getValue(_ item: Measurable) -> Double var len = new Length(30.0); var wt = new Weight(5.0); kony.print(comparator.getValue(len)); // 30 kony.print(comparator.compare(len, wt)); // 1
Extension Methods on Known Classes
Methods added to a class via extension MyClass { } in the same Swift module are fully dispatched. Call them on any instance just like regular methods:
var root = new TreeNode("root");
// extension methods available alongside regular methods
kony.print(root.allValues()); // ["root", "child1", …]
kony.print(root.size()); // total node count
kony.print(root.contains("x")); // true/false
Recursive / Tree Data Structures
Classes that reference themselves (e.g. tree nodes) work correctly. Arrays of class instances are fully wrapped with prototype access.
var root = new TreeNode("root");
var child = new TreeNode("child");
root.addChild(child);
var children = root.children(); // returns array of TreeNode objects
children[0].value; // "child"
Multiple System Framework Imports
A single Swift class file can import any number of Apple system frameworks.
Third-Party xcframework Dependencies
If your Swift framework imports another xcframework (e.g. a logging or analytics SDK), place those dependency xcframeworks in a folder and set SwiftDependencies in config.plist. The tool will import and link them automatically.
Limitations
| # | What doesn't work | Workaround |
|---|---|---|
| L1 | Same-arity Int vs Double overloads — stringify(5.5) routes to the Int variant | Use distinct method names |
| L2 | new ClassName() for failable init?** — returns a zombie object instead of null when given bad input | Use ClassName.jsnew(arg) which returns null correctly |
| L3 | Generic types — class Box<T> is skipped entirely | Provide concrete wrapper types (e.g. class StringBox) |
| L4 | Nested types — Outer.Inner is not parsed | Hoist inner types to module level |
| L5 | Operator overloads — static func +(lhs:rhs:) cannot be called | Provide a named wrapper (func add(_ a: T, _ b: T)) |
| L6 | Unnamed tuple returns — (Int, String) | Use named tuples: (value: Int, label: String) |
| L7 | inout void methods** — JS gets a dict {paramName: value} per mutated arg, not mutation of the original variable (JS has no pass-by-reference) | Read mutated values from the returned dict: var r = obj.swap(a, b); r.a; r.b |
| L8 | Object memory — Swift objects stored in the JS bridge are never automatically released | Call __nfi_swift_release(ref) manually when done with an object |
| L9 | **Pure async/await return** — calling an async method synchronously returns null | Bridge with a completion handler parameter |