Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions docs/docs/types/callbacks.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ Since JS callbacks could theoretically be called from any native Thread, callbac
class HybridMath: HybridMathSpec {
func calculate(getValue: any Callback<(), Double>) {
Task {
let result = try await getValue().await() // Double
let result = try await getValue() // Double
}
}
}
Expand All @@ -153,8 +153,9 @@ func call(callback: any Callback<(), Void>) throws {
}
```

Additionally, the call operator overload either chooses `callAndForget()` when the callback returns `Void`, or `callAsync()` when it returns
a value.
In synchronous code, the call operator chooses `callAndForget()` when the callback returns `Void`, or returns a `Promise` when it returns a
value. In async code, `try await callback(...)` waits for the result and propagates errors, just like `try await callback.callAsync(...)`.
These Swift async overloads require a `Sendable` result. Use `callAndForget()` explicitly to fire and forget from an async function.

```swift
func callVoid(callback: any Callback<(), Void>) {
Expand All @@ -163,6 +164,9 @@ func callVoid(callback: any Callback<(), Void>) {
func callResult(callback: any Callback<(), Double>) {
callback() // Promise<Double> (just like callAsync())
}
func callResultAsync(callback: any Callback<(), Double>) async throws {
let result = try await callback() // Double
}
```

:::warning
Expand Down
10 changes: 10 additions & 0 deletions packages/nitro-core/native/apple/core/Callback.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,12 @@ extension Callback where Return: Sendable {
public nonisolated(nonsending) func callAsync<each A>(_ args: repeat each A) async throws -> Return where Arguments == (repeat each A) {
return try await callAsync((repeat each args)).await()
}

/// Invokes this callback and awaits its result, throwing if the callback fails.
public nonisolated(nonsending) func callAsFunction<each A>(_ args: repeat each A) async throws -> Return
where Arguments == (repeat each A) {
return try await callAsync(repeat each args)
}
}

/// Extension to support callAsFunction() which returns a `Promise` if it has a return type
Expand All @@ -91,4 +97,8 @@ extension Callback where Return == Void {
public func callAsFunction<each A>(_ args: repeat each A) where Arguments == (repeat each A) {
callAndForget((repeat each args))
}

public nonisolated(nonsending) func callAsFunction<each A>(_ args: repeat each A) async throws where Arguments == (repeat each A) {
try await callAsync((repeat each args)).await()
}
}
15 changes: 7 additions & 8 deletions tests/standalone/nitro-test/ios/HybridTestObjectSwift.swift
Original file line number Diff line number Diff line change
Expand Up @@ -110,8 +110,7 @@ class HybridTestObjectSwift: HybridTestObjectSwiftKotlinSpec {
-> any Promise<Void>
{
return .async {
let callPromise = callback()
let resultPromise = try await callPromise.await()
let resultPromise = try await callback()
try await resultPromise.await()
}
}
Expand All @@ -132,7 +131,7 @@ class HybridTestObjectSwift: HybridTestObjectSwiftKotlinSpec {
Double
> {
return .async {
let jsResult = try await getValue().await()
let jsResult = try await getValue()
return jsResult
}
}
Expand All @@ -141,16 +140,16 @@ class HybridTestObjectSwift: HybridTestObjectSwiftKotlinSpec {
callback: any Callback<(), String>, andThenCall: any Callback<String, Void>
) throws -> any Promise<Void> {
return .async {
let jsResult = try await callback().await()
andThenCall(jsResult)
let jsResult = try await callback()
andThenCall.callAndForget(jsResult)
}
}

func callSumUpNTimes(callback: any Callback<(), Double>, n: Double) throws -> any Promise<Double> {
var result = 0.0
return .async {
for _ in 0..<max(0, Int(n)) {
let current = try await callback().await()
let current = try await callback()
result += current
}
return result
Expand All @@ -161,7 +160,7 @@ class HybridTestObjectSwift: HybridTestObjectSwiftKotlinSpec {
Double
> {
return .async {
let promise = try await callback().await()
let promise = try await callback()
let result = try await promise.await()
return result
}
Expand Down Expand Up @@ -254,7 +253,7 @@ class HybridTestObjectSwift: HybridTestObjectSwiftKotlinSpec {
callback: any Callback<(), any Promise<[Powertrain]>>
) throws -> any Promise<[Powertrain]> {
return .async {
let promise = try await callback().await()
let promise = try await callback()
return try await promise.await()
}
}
Expand Down
Loading