Swift Concurrency & Swift 6 Readiness

This page answers the three questions teams ask when evaluating whether the Zeta iOS SDK is compatible with their own Swift toolchain and concurrency posture.

This guide is for iOS developers who want to understand how the Zeta SDK behaves under Swift 6 strict concurrency, what Sendable annotations apply, and whether their app needs any changes.

  1. What Swift language version must my app use to consume the SDK?
  2. What Sendable / actor annotations do I need to satisfy on my own types that cross the SDK boundary?
  3. If I turn on Swift 6 strict concurrency mode in my app, does the SDK still build?

On this page

Minimum Swift toolchain

SurfaceMinimumNotes
swift-tools-version (SPM manifest)5.10Required to resolve the SDK's SPM package.
Xcode15.3Required for SPM resolution. XCFramework distribution works on earlier Xcode versions.
Swift language mode in your app5.x (any supported version)Swift 6 language mode is also supported. See the next section.

The SDK ships a second, version-specific manifest ([email protected]) so that:

  • On Xcode 15.3+ toolchains, SwiftPM uses Package.swift (Swift 5.10 baseline).
  • On Xcode 26+ toolchains, SwiftPM uses [email protected], where ZetaCore stays in Swift 5 language mode with upcoming-feature warnings and ZetaNotificationService is fully in Swift 6 language mode.

This means your app's choice of Swift language mode is independent of ours — you can build an app in Swift 6 language mode and still consume the SDK.

What your app must do

For the vast majority of consumers: nothing.

  • The SDK does not require your app to be in Swift 6 language mode.
  • The SDK does not require any @MainActor, nonisolated, or @unchecked Sendable annotations on your own types.
  • No SDK API asks you to pass a Sendable closure from a non-isolated context; callbacks the SDK delivers to your code are dispatched on behalf of the SDK.

Behavior under Swift 6 strict concurrency

If you enable Swift 6 strict concurrency mode in your app (either via Swift 6 language mode or via SWIFT_STRICT_CONCURRENCY = complete), the SDK continues to build and link cleanly.

  • ZetaCore ships as a pre-built module; its internal concurrency warnings do not leak into your build.
  • ZetaNotificationService is built in Swift 6 language mode against the same toolchain you use.
  • Public types exposed across the SDK boundary are designed to behave predictably in a strict-concurrency world. See Sendable expectations.

Sendable expectations

Public SDK types you hold on to follow these rules:

PatternSendable contract
Value types (enums, structs without reference-type storage) exposed by the SDKSafe to share across isolation domains.
Reference-type value models (e.g., ZTAppInboxMessage, ZTCtaAction, ZTUser)Treat as data snapshots. Do not mutate them after reading; pass copies if you need to cross an isolation boundary.
Delegates (ZTDeeplinkDelegate, ZTInAppMessageDelegate)The SDK calls your delegate on the main actor unless otherwise documented on the specific callback.

Reference-type value models should be treated as effectively immutable after the SDK hands them to you. Additional Sendable conformances will be added in future releases.

Notes on async APIs

  • App Inbox uses async throws methods on ZTAppInboxManagable. These methods are safe to call from any isolation context; pass the result back to your UI using your preferred isolation strategy.
  • All other feature areas today expose completion-handler or delegate-based APIs. Where Swift-only async / throws affordances exist, the page for that feature calls them out explicitly.

Background & rationale

The SDK is migrated toward Swift 6 target-by-target rather than all at once. The design choice behind the dual-manifest setup is:

  • ZetaNotificationService — small, self-contained, no Obj-C interop. It is fully in Swift 6 language mode in [email protected].
  • ZetaCore — large, Obj-C-interoperable surface. It runs in Swift 5 language mode with upcoming-feature flags enabled as warnings (StrictConcurrency, ExistentialAny, InferSendableFromCaptures, DisableOutwardActorInference, and others). A future release will switch to Swift 6 language mode.

For consumers this has two practical effects:

  1. Backward compatibility is free. If you are on Xcode 15.3+ you see the same SDK you always have.
  2. Forward compatibility is live. If you are on Xcode 26+ in Swift 6 language mode, the SDK already carries the strict-concurrency and Sendable work we've done to date, and the remaining warnings are internal to the SDK — they don't reach your build.

See also