Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions client-sdks/reference/swift.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
</CardGroup>

<Note>
Earlier versions of the Swift SDK (up to v1.13) shipped a PowerSync Kotlin XCFramework under the hood and abstracted it behind Swift protocols.

Check warning on line 29 in client-sdks/reference/swift.mdx

View check run for this annotation

Mintlify / Mintlify Validation (powersync) - vale-spellcheck

client-sdks/reference/swift.mdx#L29

Did you really mean 'XCFramework'?

From v1.14 onward, the Kotlin dependency has been removed entirely. The SDK is now implemented natively in Swift, with the PowerSync sync protocol and SQLite extension handled by our [Rust core](https://github.com/powersync-ja/powersync-sqlite-core).
</Note>
Expand Down Expand Up @@ -277,6 +277,33 @@

The `DefaultLogger` supports the following severity levels: `.debug`, `.info`, `.warn`, `.error`.

## App Groups and App Extensions

By default, the Swift SDK stores databases in `applicationSupportDirectory`. If you want to share local databases
between multiple apps in an app group, provide an absolute path (starting with `/`) as `dbFilename` when calling
`PowerSyncDatabase`.
The path should point towards a file in the app group's [shared container](https://developer.apple.com/documentation/xcode/configuring-app-groups#Access-an-app-groups-shared-container).

<Info>Support for app groups and extensions was added in version 1.15, and is experimental.</Info>

With app groups and extensions, multiple processes might access the database at the same time. SQLite uses shared memory
and file locking to make this safe, but there are still concerns that aren't relevant when the database is only accessed
from a single context:

1. Concurrent writes to the database are not allowed. Within a process, the PowerSync SDK uses Swift actors to schedule
writes. Outside of SQLite using file locks, there is no additional coordination for multi-process access.
- Consider using [`PRAGMA busy_timeout`](https://sqlite.org/pragma.html#pragma_busy_timeout) to make SQLite wait longer.
- Be ready to handle `SQLITE_BUSY` errors if multiple processes attempt to write to the database.
2. Do not call `connect()` in more than one process! If two processes attempt to connect to the PowerSync service for
the same database, this wastes resources and can also lead to concurrency issues. If you share databases with extensions
or app groups, ensure there is only context responsible for connecting.
3. Avoid multiple versions of the Swift SDK: While the SQLite file format is stable and databases can safely be accessed
from multiple processes using their own SQLite version, the PowerSync SDK is not designed with this in mind.
In particular, opening the same database file from multiple processes can cause PowerSync-internal migrations to get
reverted.
This is not a concern for app extensions released as part of the same bundle, but something to be aware of for
app groups.

## Additional Usage Examples

For more usage examples including accessing connection status, monitoring sync progress, and waiting for initial sync, see the [Usage Examples](/client-sdks/usage-examples) page.
Expand Down
23 changes: 5 additions & 18 deletions client-sdks/usage-examples.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -879,26 +879,19 @@ import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-call
import PowerSync

struct PowerSyncConnectionIndicator: View {
private let powersync: any PowerSyncDatabaseProtocol
@State private var connected: Bool = false
private let status: ObservableSyncStatus

init(powersync: any PowerSyncDatabaseProtocol) {
self.powersync = powersync
self.status = powersync.currentStatus.observable
}

var body: some View {
let connected = status.connected
let iconName = connected ? "wifi" : "wifi.slash"
let description = connected ? "Online" : "Offline"

Image(systemName: iconName)
.accessibility(label: Text(description))
.task {
self.connected = powersync.currentStatus.connected

for await status in powersync.currentStatus.asFlow() {
self.connected = status.connected
}
}
}
}
```
Expand Down Expand Up @@ -1391,12 +1384,11 @@ import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-call

```swift
struct SyncProgressIndicator: View {
private let powersync: any PowerSyncDatabaseProtocol
private let status: ObservableSyncStatus
private let priority: BucketPriority?
@State private var status: SyncStatusData? = nil

init(powersync: any PowerSyncDatabaseProtocol, priority: BucketPriority? = nil) {
self.powersync = powersync
self.status = powersync.currentStatus.observable
self.priority = priority
}

Expand All @@ -1417,11 +1409,6 @@ import JavaScriptCallbackWatch from '/snippets/basic-watch-query-javascript-call
Text("Downloaded \(progress.downloadedOperations) out of \(progress.totalOperations)")
}
}
}.task {
status = powersync.currentStatus
for await status in powersync.currentStatus.asFlow() {
self.status = status
}
}
}
}
Expand Down