I have an interactive Widget for iOS 17+ that when a user taps in a Widget button, the AppIntent should contact the backend and perform an action, and retrieve a result, either success or failure. This response should update the widget accordingly.
The API:
The backend connection is made through an old Obj-C lib that deals with certificates, hashes, encryption, etc., and the API is using completion blocks. Migrating to async await is not an option in this case.
What have I tried:
Adapt the perform() function of the AppIntent to perform the network request, wait for the completion and return, using withCheckedThrowingContinuation to bridge between the completions and async await.
func perform() async throws -> some IntentResult {
return try await withCheckedThrowingContinuation { continuation in
fetcher.trigger() { result in
switch result {
case .success:
continuation.resume(returning: NetworkRequestResult.success(message: "Request successful"))
case .failure(let error):
continuation.resume(throwing: error)
}
}
}
}
The NetworkRequestResult was an attempt to create a type that would comform to the IntentResult protocol, as all my attempts using .result() were failing with the compiler:
struct NetworkRequestResult: IntentResult {
var value: Never? { nil }
var description: String
static func success(message: String) -> NetworkRequestResult {
NetworkRequestResult(description: message)
}
static func failure(message: String) -> NetworkRequestResult {
NetworkRequestResult(description: message)
}
}
The debugger points out a crash in case of a successful response inside the completion block, “Fatal error: Unsupported IntentResult type”. Any .result() attempts fail with the compiler “Cannot infer contextual base in reference to member ‘result'”.
How can I handle the completions in the AppIntent perform method?