Skip to content

Commit daa5601

Browse files
itsniperclaude
andcommitted
Update DocC for suspending authorize, connect error, and bounded discoveries
- GettingStarted: authorizeBluetooth() now suspends until the user responds and returns only when authorized (and is cancellable) — document the new behavior in place of the old "no-op" note. - GettingStarted: the connect(to:) example now also handles PeripheralError.bluetoothUnavailable. - GettingStarted & Concurrency: note that the peripheralDiscoveries feed is bounded (drops the oldest pending advertisements under backpressure). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent baa0896 commit daa5601

2 files changed

Lines changed: 10 additions & 3 deletions

File tree

Sources/ReliaBLE/Documentation.docc/GettingStarted.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,9 @@ iOS requires permission from the user for BLE access. To set this up in your pro
6969
```
7070
The current state is replayed as the stream's first element, so a new subscriber immediately observes the latest state.
7171

72-
Note: The authorization prompt will only appear once. It is safe to call `ReliaBLEManager.authorizeBluetooth()` multiple times. If the user already granted permission it will be a no-op. If the user denies permission, they'll need to enable it manually through the Settings app.
72+
Note: When authorization has not yet been determined, `ReliaBLEManager.authorizeBluetooth()` presents the system prompt and **suspends until the user responds** — it returns normally only once access is granted, and throws ``AuthorizationError`` if the user denies or access is restricted. A successful return therefore means Bluetooth is authorized. Cancelling the calling task unblocks the suspension with a `CancellationError`.
73+
74+
The prompt only appears once, and it is safe to call the method multiple times: if the user already granted permission the call returns immediately; if they denied it, they'll need to re-enable access through the Settings app.
7375

7476
## Scanning for Peripherals
7577

@@ -125,7 +127,7 @@ While scanning, ReliaBLE surfaces results two ways:
125127
- ``ReliaBLEManager/peripheralDiscoveries`` emits a lightweight ``PeripheralDiscoveryEvent`` for every advertisement received — useful when you need to process individual advertisement packets.
126128
- ``ReliaBLEManager/discoveredPeripherals`` emits the current de-duplicated list of ``Peripheral`` values each time it changes.
127129

128-
Both are `AsyncStream`s. Each property access returns a *fresh, independent* stream, so multiple subscribers are supported by design — consume each with `for await`, typically inside a SwiftUI `.task { … }` (which cancels the loop automatically when the view disappears). ``ReliaBLEManager/state`` and ``ReliaBLEManager/discoveredPeripherals`` replay their latest value to every new subscriber; ``ReliaBLEManager/peripheralDiscoveries`` does **not** replay, so subscribe before you start scanning to avoid missing early advertisements.
130+
Both are `AsyncStream`s. Each property access returns a *fresh, independent* stream, so multiple subscribers are supported by design — consume each with `for await`, typically inside a SwiftUI `.task { … }` (which cancels the loop automatically when the view disappears). ``ReliaBLEManager/state`` and ``ReliaBLEManager/discoveredPeripherals`` replay their latest value to every new subscriber; ``ReliaBLEManager/peripheralDiscoveries`` does **not** replay, so subscribe before you start scanning to avoid missing early advertisements. The discoveries feed is also bounded, so a subscriber that consumes slower than advertisements arrive drops the oldest pending events rather than growing memory without bound.
129131

130132
A ``Peripheral`` is an immutable, `Sendable` value snapshot: it carries the peripheral's ``Peripheral/id``, ``Peripheral/name``, ``Peripheral/rssi``, ``Peripheral/lastSeen``, and a strongly-typed ``AdvertisementData`` rather than a raw `[String: Any]` dictionary. Because it is a value type, it is safe to hand directly to your UI.
131133

@@ -149,6 +151,9 @@ do {
149151
} catch PeripheralError.notFound {
150152
// The snapshot is stale — its underlying peripheral reference was invalidated
151153
// (for example, after a Bluetooth reset). Re-scan to rediscover it.
154+
} catch PeripheralError.bluetoothUnavailable {
155+
// Bluetooth has not been set up yet (for example, not authorized). Authorize and wait
156+
// for the `.ready` state before retrying.
152157
}
153158
```
154159

Sources/ReliaBLE/Documentation.docc/Topics/Concurrency.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,9 @@ Replay semantics differ per stream:
7171
- ``ReliaBLEManager/discoveredPeripherals`` — replays the **latest** value to new
7272
subscribers (`.bufferingNewest(1)`).
7373
- ``ReliaBLEManager/peripheralDiscoveries`` — does **not** replay; a new
74-
subscriber only receives discoveries that occur after it begins iterating.
74+
subscriber only receives discoveries that occur after it begins iterating. Its
75+
buffer is bounded (`.bufferingNewest`), so a slow subscriber drops the oldest
76+
pending advertisements rather than growing memory without bound.
7577

7678
Because each call returns an independent stream, multiple parts of your app can
7779
observe the same surface concurrently without interfering with one another.

0 commit comments

Comments
 (0)