blePowered() lit le manager, search() lit le sujet : ce ne sont pas les mêmes
Le message n'avait pas bougé alors qu'il n'aurait plus dû pouvoir apparaître : attendre `blePowered()` avait donc réussi, et le publisher se taisait quand même. C'est ce qui a montré l'erreur. `blePowered()` rend `manager.state == .poweredOn` — l'état de CoreBluetooth. Or `search()` filtre sur `bleStateSubject`, alimenté uniquement par `centralManagerDidUpdateState`. Le manager peut donc être allumé sans que le délégué ait publié quoi que ce soit : le sujet reste à `.unknown`, le filtre bloque, le publisher se tait. Attendre `blePowered()` ne prouvait rien sur ce que `search()` allait voir — c'était la mauvaise sonde. On attend désormais sur `monitorBleState()`, qui est public et qui EST la source lue par search(). `blePowered()` garde un seul rôle : instancier la lazy pour que le délégué puisse tourner. L'attente porte son échéance elle-même plutôt que de passer par avecEcheance : le listener n'est pas Sendable et le faire traverser une TaskGroup se heurterait à la concurrence stricte de Swift 6. Et `BoiteJeton` garantit une reprise unique de la continuation — deux chemins de sortie concurrents (l'état publié et l'échéance), et reprendre deux fois est un crash, pas un avertissement. 82 tests au vert. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -182,10 +182,18 @@ piège suivant.
|
||||
depuis le délégué. Si CoreBluetooth appelle le délégué avant que l'initialisation
|
||||
de la lazy soit terminée, la propriété se réentre.
|
||||
|
||||
⇒ **Séquence correcte** : créer le listener, poser `scanPreFilter`, réveiller la
|
||||
lazy en sondant `blePowered()` jusqu'à ce qu'elle réponde vrai — hors de tout
|
||||
abonnement — et seulement ensuite appeler `search()`, une fois, sur toute la
|
||||
durée. Un abonnement par tranche relancerait le cycle
|
||||
**3. `blePowered()` et `search()` ne lisent pas la même chose.** `blePowered()`
|
||||
rend `manager.state == .poweredOn` — l'état de CoreBluetooth. `search()` filtre
|
||||
sur `bleStateSubject`, qui n'est alimenté que par `centralManagerDidUpdateState`.
|
||||
Le manager peut donc être allumé sans que le délégué ait publié quoi que ce
|
||||
soit : le sujet reste à `.unknown` et le filtre bloque. Attendre `blePowered()`
|
||||
ne prouve rien sur ce que `search()` verra.
|
||||
|
||||
⇒ **Séquence correcte** : créer le listener, poser `scanPreFilter`, appeler
|
||||
`blePowered()` **une fois** (son seul rôle : instancier la lazy pour que le
|
||||
délégué puisse tourner), puis attendre sur **`monitorBleState()`** — public, et
|
||||
c'est la source que `search()` lit — jusqu'à `.poweredOn`. Seulement ensuite,
|
||||
`search()`, une fois, sur toute la durée. Un abonnement par tranche relancerait le cycle
|
||||
`addClient()`/`removeClient()` du scanner et l'empêcherait de découvrir quoi que
|
||||
ce soit.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user