← Files FirebaseARCHIVED FILE
reference/sdk_ios.md
4.23 KB · Sep 30, 2026 · 23:02 UTC
# iOS SDK
Consult this file when writing iOS application code (Swift) that interacts with
the SQL Connect backend.
### Best Practices for Agents
- **Understand Operation Storage**: SQL Connect queries and mutations are stored
on the server like Cloud Functions. **Whenever you update operations, you must
regenerate the SDK and redeploy services** that use it to avoid breaking
clients.
- **Resilient Enum Handling**: The generated SDK forces handling of unknown
values by adding an `._UNKNOWN` case. Swift enforces exhaustive switch
statements, so you must handle this case.
- **Observable Macro**: By default, query refs support the `@Observable` macro
(iOS 17+), making them ideal for binding to SwiftUI views. The bindable query
results are available in the `data` variable of the query ref.
- **Handle Errors**: Use `try await` with operation execution as they are
asynchronous and may throw errors.
### Dependencies (Package.swift or SPM)
Configure the generated SDK as a package dependency in Xcode.
### Initialization
Retrieve the generated connector instance:
```swift
import FirebaseCore
import FirebaseDataConnect
// Assuming connector name is 'movies' in connector.yaml
// The connector name is the lower camel case connectorId defined in connector.yaml suffixed with the word 'Connector'
let connector = DataConnect.moviesConnector
// For local development with emulator
// Defaults to 127.0.0.1:9399
connector.useEmulator()
// Or specify a non-default port:
// connector.useEmulator(port: 9999)
```
### Calling Operations
#### Basic Query
```swift
let result = try await connector.listMovies.execute()
for movie in result.data.movies {
print(movie.title)
}
```
#### Mutation
```swift
let mutationResult = try await connector.createMovieMutation.execute(
title: "Empire Strikes Back",
releaseYear: 1980,
genre: "Sci-Fi",
rating: 5
)
```
### Resilient Enum Handling
Handle generated enums exhaustively, including the `._UNKNOWN` case.
```swift
do {
let result = try await DataConnect.moviesConnector.listMovies.execute()
if let data = result.data {
for movie in data.movies {
switch movie.aspectratio {
case .ACADEMY: print("academy")
case .WIDESCREEN: print("widescreen")
case .ANAMORPHIC: print("anamorphic")
case ._UNKNOWN(let unknownAspect): print("Unknown: \(unknownAspect)")
}
}
}
} catch {
// handle error
}
```
### Client-Side Caching
Enable caching in `connector.yaml` to reduce requests, support offline
scenarios, enable realtime support for queries.
```yaml
generate:
swiftSdk:
outputDir: "../ios"
package: "FirebaseDataConnectGenerated"
clientCache:
maxAge: 5s
storage: persistent # Default for iOS is persistent
```
Use cache policies in code:
```swift
try await execute(fetchPolicy: .cacheOnly)
try await execute(fetchPolicy: .serverOnly)
```
### Subscriptions (Realtime)
#### SwiftUI Example
```swift
import Combine
import SwiftUI
struct ListMovieView: View {
// QueryRef has the Observable attribute, so its properties will
// automatically trigger updates on changes.
private var queryRef = connector.listMoviesByGenreQuery.ref(genre: "Sci-Fi")
// Store the handle to unsubscribe from query updates.
@State private var querySub: AnyCancellable?
var body: some View {
VStack {
// Use the query results in a View.
ForEach(queryRef.data?.movies ?? [], id: \.id) { movie in
Text(movie.title)
}
}
.onAppear {
// Subscribe to the query for updates using the Observable macro.
Task {
do {
querySub = try await queryRef.subscribe().sink { _ in }
} catch {
print("Error subscribing to query: \(error)")
}
}
}
.onDisappear {
querySub?.cancel()
}
}
}
```
### Data Type Mapping Reference
- GraphQL `UUID` -> Swift `UUID`
- GraphQL `Date` -> Swift `FirebaseDataConnect.LocalDate`
- GraphQL `Timestamp` -> Swift `FirebaseCore.Timestamp`
- GraphQL `Int` -> Swift `Int`
- GraphQL `Float` -> Swift `Double`
- GraphQL `Boolean` -> Swift `Bool`
SHA-256: cc972c288be5e0b833e1f7e4e9ced324e06e412f77086baef6630dab62f93a2c