Comments (1)
Hi, thanks for the question :)
A quick look at the state machine logs you pasted suggests that connect
is being called more than once on the same instance.
[ERROR] No transition found for (bluetoothConnected, didConnect(<JacquardSDK.PeripheralImplementation: 0x282988940>))
What this is saying is that the current state of the tag state machine is bluetoothConnected
, and yet it is being asked to handle the message didConnect
-- which absent a bug in either the state machine or CoreBluetooth should only be possible if connect
is called more than once.
You're callingconnect
in a SwiftUI View struct init
- these are simple value objects which may be (re)created more than once so it's likely that's what's happening here.
In fact when I run your code connected to a single tag I see three instances of tag connect request
in the console.
There are two ways you can solve this - one is to write a SwiftUI State Object wrapper for your connection/tag logic (ie. something that conforms to ObservableObject. I've done this before and it works but feels like a bunch of boilerplate code.
Since you're targeting iOS 16 I'd suggest using the (new in iOS 15) .task
SwiftUI modifier for calling async/await code for a view (SwiftUI connects very nicely with the new structured concurrency features). This means you'll need to convert the Combine publisher to an AsyncStream somehow. It's pretty easy to do that by hand (see below) but it should also be possible to write a generic bridging function.
Since you're using the tag ID connection method, something like this should work:
Create an async/await wrapper for connect
extension JacquardManager {
func asyncConnect(_ identifier: UUID) -> AsyncThrowingStream<TagConnectionState, Error> {
AsyncThrowingStream { continuation in
let cancellable = self.connect(identifier)
.sink { completion in
switch completion {
case .finished:
continuation.finish()
case .failure(let error):
continuation.finish(throwing: error)
}
} receiveValue: { connectionState in
continuation.yield(connectionState)
}
continuation.onTermination = { @Sendable _ in
cancellable.cancel()
}
}
}
}
Triggering connection and looping over the AsyncThrowingSequence
struct ConnectingView: View {
@State private var connectedTag: ConnectedTag? = nil
@State private var lastConnectionStateDescription = "Preparing to connect..."
private var tagIdentifier: UUID
private var jqManager: JacquardManager
init(manager: JacquardManager, tagId: UUID) {
self.tagIdentifier = tagId
self.jqManager = manager
}
var body: some View {
VStack {
if let connectedTag = connectedTag {
Text("Connected to \(connectedTag.displayName)")
} else {
Text(lastConnectionStateDescription)
}
}
.task {
do {
let connectionStream = jqManager.asyncConnect(tagIdentifier)
for try await connectionState in connectionStream {
print("\(connectionState)")
switch connectionState {
case .connected(let tag):
connectedTag = tag
default:
connectedTag = nil
lastConnectionStateDescription = "\(connectionState)"
}
}
} catch {
print("error during connection: \(error)")
}
}
}
}
Dropping this into your repository seems to work with an adhoc test, including tag reconnection (you'll want to retain and pass around the connectionStream
instance not the connectedTag
instance so that you handle reconnections like the Combine examples do. If you search the usual places you'll find some people have written helper functions for AsyncSequence
that provide Combine/Rx like operators if that's helpful for your design.
from jacquardsdkios.
Related Issues (2)
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from jacquardsdkios.