Reputation: 1001
I'm trying to use MultiPeer Connectivity framework with swift ui and am having issues with using ForEach in my view. I have a singleton that I'm using to track connected users in an array:
class MPCManager: NSObject {
static let instance = MPCManager()
var devices: [Device] = []
...
And my device class:
class Device: NSObject {
let peerID: MCPeerID
var session: MCSession?
var name: String
var state = MCSessionState.notConnected
var lastMessageReceived: Message?
...
}
When the MultiPeer connectivity frame finds new peers the MPCManager is appending new devices to the array. I have confirmed this in the debugger. The problem comes when I try to display the devices in a list. Here is the code that I'm using:
struct ContentView : View {
var devices: [Device] = MPCManager.instance.devices
var body: some View {
List {
ForEach(self.devices.identified(by: \.name)) { device in
Text(device.name)
}
}
}
}
When the app starts, the list is displayed but it is empty. When I put a breakpoint in the view code inside the ForEach execution never stops. When I change the array to a hardcoded list of values, it displays just fine. I have also tried referencing the array from the static instance directly in my view like this:
ForEach(self.devices.identified(by: \.name)) { device in
Text(device.name)
}
Still nothing. I'm very new to swift so there may be something easy that I'm missing but I just don't see it. Any ideas?
Upvotes: 3
Views: 6703
Reputation: 7800
There are a couple issues here as far as I can tell.
First, I would suggest you try this with your MPCManager
:
import SwiftUI
import Combine
class MPCManager: NSObject, BindableObject {
var didChange = PassthroughSubject<Void, Never>()
var devices: [Device] = [] {
didSet {
self.didChange.send(())
}
}
}
Then, in your ContentView
, do this:
struct ContentView : View {
@ObjectBinding var manager: MPCManager = MPCManager()
var body: some View {
List {
ForEach(self.manager.devices.identified(by: \.name)) { device in
Text(device.name)
}
}
}
}
The main difficulty with answering your question is that I can't run your code. Your question would be more useful to others (and much easier to answer) if you could distill your code down to something that people who might know the answer could just copy and paste into Xcode.
As of Xcode Beta 4, identified(by:)
has been replaced by specific initializers for List
and ForEach
, and as of Xcode Beta 5, BindableObject
has been replaced by ObservableObject
and @ObjectBinding
has been replaced by @ObservedObject
.
import SwiftUI
import Combine
class MPCManager: NSObject, ObservableObject {
var objectWillChange = PassthroughSubject<Void, Never>()
var devices: [Device] = [] {
willSet {
self.objectWillChange.send()
}
}
}
struct ContentView : View {
@ObservedObject var manager: MPCManager = MPCManager()
var body: some View {
List {
ForEach(self.manager.devices, id: \.name) { device in
Text(device.name)
}
}
}
}
Upvotes: 6