> For the complete documentation index, see [llms.txt](https://docs.ecommerce.seb.ee/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ecommerce.seb.ee/integration/mobile-sdk/ios-sdk/using-the-sdk/objective-c-and-swiftui.md).

# Objective-C and SwiftUI

Call the SDK from Objective-C, from SwiftUI, and from async code, and use the delegate instead of a completion block.

Use this guide if your call site is not a plain Swift `UIViewController`.

The public API is Objective-C compatible throughout, which is what makes Objective-C support possible and what rules out a Swift-only or SwiftUI-only surface. The bridges below cover the gap.

***

## Objective-C

In Objective-C the types carry an `EGW` prefix. `PaymentKit` is `EGWPaymentKit`, `Configuration` is `EGWConfiguration`, and so on.

### Hosted checkout

```objc
@import EGWPay;

EGWConfiguration *configuration =
    [[EGWConfiguration alloc] initWithApiBaseURL:[NSURL URLWithString:@"https://your-backend.example.com"]
                                     environment:EGWEnvironmentSandbox];

EGWPaymentKit *paymentKit = [[EGWPaymentKit alloc] initWithConfiguration:configuration];

EGWPaymentRequest *request =
    [[EGWPaymentRequest alloc] initWithPaymentId:paymentId
                                 verificationKey:verificationKey
                                     checkoutURL:checkoutURL
                                       returnURL:[NSURL URLWithString:@"myapp://checkout/return"]];

[paymentKit startPayment:request from:self completion:^(EGWPaymentResult *result) {
    switch (result.outcome) {
        case EGWPaymentOutcomeSucceeded:
            [self showReceiptWithReference:result.orderNumber ?: result.paymentId];
            break;
        case EGWPaymentOutcomeFailed:
            [self showFailure:result.error];
            break;
        case EGWPaymentOutcomeCancelled:
            break;
        case EGWPaymentOutcomeUnresolved:
            [self confirmWithBackend:result.paymentId];
            break;
    }
}];
```

### Native card form

```objc
EGWConfiguration *configuration =
    [[EGWConfiguration alloc] initWithApiBaseURL:[NSURL URLWithString:@"https://your-backend.example.com"]
                              checkoutAPIBaseURL:[NSURL URLWithString:@"https://sandbox-api.example.com"]
                                 checkoutBaseURL:[NSURL URLWithString:@"https://sandbox-checkout.example.com"]
                                     environment:EGWEnvironmentSandbox];

EGWPaymentKit *paymentKit = [[EGWPaymentKit alloc] initWithConfiguration:configuration];

EGWCardInput *card = [[EGWCardInput alloc] init];
card.cardholderName = self.nameField.text;
card.cardNumber = self.numberField.text;
card.expiryMonth = self.expiryField.month;
card.expiryYear = self.expiryField.year;
card.securityCode = self.securityCodeField.text;

EGWCardPaymentRequest *request =
    [[EGWCardPaymentRequest alloc] initWithPaymentId:paymentId
                                     verificationKey:verificationKey];

[paymentKit startCardPayment:request card:card from:self completion:^(EGWPaymentResult *result) {
    // Same outcome handling as above.
}];
```

### Using a delegate instead of a block

Both entry points have a delegate-based overload. The delegate is held weakly, so keep your own strong reference to it.

```objc
@interface CheckoutViewController () <EGWPaymentDelegate>
@end

@implementation CheckoutViewController

- (void)pay {
    [self.paymentKit startPayment:self.request from:self delegate:self];
}

- (void)paymentDidFinish:(EGWPaymentResult *)result {
    // Called once, on the main thread, after the SDK's interface is dismissed.
}

@end
```

The same pairing exists in Swift: `startPayment(_:from:delegate:)` and `startCardPayment(_:card:from:delegate:)` take a `PaymentDelegate` and call `paymentDidFinish(_:)`.

***

## SwiftUI

`startPayment` presents from a `UIViewController`, which SwiftUI does not hand you directly. Bridge it once:

```swift
import SwiftUI
import UIKit

/// Exposes the nearest UIKit view controller to SwiftUI code.
struct ViewControllerProvider: UIViewControllerRepresentable {
    final class Holder: UIViewController {}

    @Binding var controller: UIViewController?

    func makeUIViewController(context: Context) -> Holder {
        let holder = Holder()
        DispatchQueue.main.async { controller = holder }
        return holder
    }

    func updateUIViewController(_ uiViewController: Holder, context: Context) {}
}
```

Then use it wherever you start a payment:

```swift
struct CheckoutButton: View {
    @State private var presenter: UIViewController?
    let request: PaymentRequest
    let paymentKit: PaymentKit

    var body: some View {
        Button("Pay") {
            guard let presenter else { return }
            paymentKit.startPayment(request, from: presenter) { result in
                // Handle the outcome.
            }
        }
        .background(ViewControllerProvider(controller: $presenter).frame(width: 0, height: 0))
    }
}
```

**Keep a presentation slot free.** If your checkout screen is itself inside a `.sheet` or `.fullScreenCover`, presenting the SDK from it can fail. Push the checkout screen instead.

### Bridging to `async`

The SDK is completion-based. Wrap it once:

```swift
func pay(_ request: PaymentRequest, from presenter: UIViewController) async -> PaymentResult {
    await withCheckedContinuation { continuation in
        paymentKit.startPayment(request, from: presenter) { continuation.resume(returning: $0) }
    }
}
```

This is safe precisely because the completion fires exactly once. Resuming a continuation twice would crash, and the callback contract rules that out.

### Wrapping the card text fields

The card text fields are ordinary `UITextField` subclasses, so they wrap like any other:

```swift
struct CardNumberField: UIViewRepresentable {
    @Binding var text: String

    func makeUIView(context: Context) -> CardNumberTextField {
        let field = CardNumberTextField()
        field.addTarget(context.coordinator,
                        action: #selector(Coordinator.changed),
                        for: .editingChanged)
        return field
    }

    func updateUIView(_ uiView: CardNumberTextField, context: Context) {}

    func makeCoordinator() -> Coordinator { Coordinator(text: $text) }

    final class Coordinator: NSObject {
        @Binding var text: String
        init(text: Binding<String>) { _text = text }
        @objc func changed(_ sender: CardNumberTextField) { text = sender.text ?? "" }
    }
}
```

***

## Next steps

* [API reference](/integration/mobile-sdk/ios-sdk/reference/api.md) - every type under both its Swift and Objective-C name.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.ecommerce.seb.ee/integration/mobile-sdk/ios-sdk/using-the-sdk/objective-c-and-swiftui.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
