One Logo Pool Ball
AppIntents · IOS API REFERENCE

CancellableIntent

protocol · iOS 26.4+ · SDK 27.1

protocol CancellableIntent : AppIntent

An interface to support the graceful cancellation of your app intent’s task. This protocol adds cancellation support to your app intent types. Use it to let the system know that you need additional time to perform cleanup operations when your app intent receives a cancellation notification. To use this protocol, use the ``CancellableIntent/withIntentCancellationHandler(operation:onCancel:isolation:)`` method to wrap your app intent’s task. With this method in place, the system gives your code extra time to handle cancellation before the app intent's task ends. The system can cancel an app intent for the following reasons: * The app intent didn’t report progress and exceeded its 30-second runtime limit. * Someone monitoring the progress of the app intent in Siri, Live Activities, or Shortcuts chose to cancel the task. Swift provides the standard <doc://com.apple.documentation/documentation/swift/withtaskcancellationhandler(handler:operation:)> function for tasks to handle cancellation. You can use that function in your app intent’s ``AppIntent/perform()`` method to perform any cleanup tasks if you don’t need to know the reason cancellation occurred. If you want to know the reason for cancellation, use the ``CancellableIntent/withIntentCancellationHandler(operation:onCancel:isolation:)`` method that this protocol offers instead. When cancellation occurs, stop your app intent’s current task, release any allocated memory or resources, save intermediate state as needed, and write out any relevant diagnostic information related to the cancellation. The following example shows a payment-processing app intent and the basic code it uses to perform its task. The app intent’s ``AppIntent/perform()`` method calls the ``CancellableIntent/withIntentCancellationHandler(operation:onCancel:isolation:)`` method to process the payment and handle cancellation if it occurs. The cancellation handler performs different tasks based on whether the someone canceled the operation deliberately or the system timed out. ```swift enum PaymentMethod: String, AppEnum { case creditCard case debitCard static var typeDisplayRepresentation = TypeDisplayRepresentation(name: "Payment Method") static var caseDisplayRepresentations: [PaymentMethod: DisplayRepresentation] = [ .creditCard: "Credit Card", .debitCard: "Debit Card" ] } class PaymentService { func initiateTransaction(_ id: UUID, amount: Decimal) async throws { // Initiate payment transaction } func authorize(_ id: UUID, method: PaymentMethod) async throws { // Authorize payment } func process(_ id: UUID) async throws { // Process payment } func rollback(_ id: UUID, reason: String) async throws { // Roll back transaction } func cancel(_ id: UUID, reason: String) async throws { // Cancel transaction } } struct ProcessPaymentIntent: AppIntent, ProgressReportingIntent, CancellableIntent { static var title: LocalizedStringResource = "Process Payment" @Parameter var amount: Decimal @Parameter var paymentMethod: PaymentMethod private let paymentService = PaymentService() func perform() async throws -> some IntentResult & ProvidesDialog { let transactionID = UUID() return try await withIntentCancellationHandler { updateProgress(fractionCompleted: 0.0, message: "Initiating payment...") try await paymentService.initiateTransaction(transactionID, amount: amount) updateProgress(fractionCompleted: 0.3, message: "Authorizing payment...") try await paymentService.authorize(transactionID, method: paymentMethod) updateProgress(fractionCompleted: 0.7, message: "Processing payment...") try await paymentService.process(transactionID) updateProgress(fractionCompleted: 1.0, message: "Payment complete") return .result(dialog: "Payment of \(amount) processed successfully") } onCancel: { reason in Task { switch reason { case .timeout: try? await paymentService.rollback(transactionID, reason: "timeout") case .userCancelled: try? await paymentService.cancel(transactionID, reason: "user_cancelled") default: try? await paymentService.cancel(transactionID, reason: "unknown") } } } } } ``` > Important: Design your cancellation handlers to finish their tasks quickly. On all > platforms except macOS, the system can still suspend the process shortly after cancellation. > However, supporting this protocol provides additional time compared to app intents that > don’t support this protocol.

Members (1)

method · iOS 26.4+

withIntentCancellationHandler

Swift declaration
func withIntentCancellationHandler<T>(operation: () async throws -> T, onCancel handler: @Sendable (IntentCancellationReason) -> Void, isolation: isolated (any Actor)? = #isolation) async rethrows -> T

Runs an operation with a cancellation handler that receives a cancellation reason. - Parameters: - operation: The closure with the operation to run. Use this closure to run the code for your app intent’s task. - handler: The closure to run when cancellation occurs. Use this closure to respond to the cancellation and perform any required cleanup. The closure receives a parameter with the cancellation reason and returns no value. - isolation: The actor isolation for the operation. If you don’t specify a value, the system uses the current isolation context. - Returns: The value you return from the `operation` closure. - Throws: Rethrows any error thrown by the operation. Use this method to handle cancellation in an app intent’s ``AppIntent/perform()`` method when you also want to know the reason for cancellation. If cancellation occurs due to a timeout or someone canceling the operation, the system runs your `handler` and gives you a little extra time to perform any cleanup. If you don't need to know the cancellation reason, you can use the standard Swift <doc://com.apple.documentation/documentation/swift/withtaskcancellationhandler(handler:operation:)> method for tasks instead.

Skipped declarations

No declarations were skipped in this snapshot.

All AppIntents types →