SwiftUI ForEach 在数组更改时不迭代。列表为空,ForEach 为 运行
SwiftUI ForEach not iterating when array changes. List is empty and ForEach does run
我正在尝试将 MultiPeer Connectivity 框架与 swift ui 一起使用,但在我看来使用 ForEach 时遇到问题。我有一个单例,用于跟踪数组中的已连接用户:
class MPCManager: NSObject {
static let instance = MPCManager()
var devices: [Device] = []
...
我的设备class:
class Device: NSObject {
let peerID: MCPeerID
var session: MCSession?
var name: String
var state = MCSessionState.notConnected
var lastMessageReceived: Message?
...
}
当 MultiPeer 连接框架找到新的对等点时,MPCManager 正在将新设备附加到阵列。我已经在调试器中确认了这一点。当我尝试在列表中显示设备时出现问题。这是我正在使用的代码:
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)
}
}
}
}
当应用程序启动时,显示列表但它是空的。当我在 ForEach 执行中的视图代码中放置断点时,永远不会停止。当我将数组更改为硬编码的值列表时,它显示得很好。我也试过在我的视图中直接从静态实例引用数组,如下所示:
ForEach(self.devices.identified(by: \.name)) { device in
Text(device.name)
}
仍然没有。我是 swift 的新手,所以我可能缺少一些简单的东西,但我只是没有看到它。有什么想法吗?
据我所知这里有几个问题。
首先,我建议您使用 MPCManager
:
试试这个
import SwiftUI
import Combine
class MPCManager: NSObject, BindableObject {
var didChange = PassthroughSubject<Void, Never>()
var devices: [Device] = [] {
didSet {
self.didChange.send(())
}
}
}
然后,在您的 ContentView
中执行此操作:
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)
}
}
}
}
回答您的问题的主要困难是我无法 运行 您的代码。如果您可以将代码提炼成可能知道答案的人可以复制并粘贴到 Xcode.
中的内容,那么您的问题对其他人会更有用(并且更容易回答)
更新
从 Xcode Beta 4 开始,identified(by:)
已被 List
和 ForEach
的特定初始值设定项取代,从 Xcode Beta 5 开始, BindableObject
已替换为 ObservableObject
,@ObjectBinding
已替换为 @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)
}
}
}
}
我正在尝试将 MultiPeer Connectivity 框架与 swift ui 一起使用,但在我看来使用 ForEach 时遇到问题。我有一个单例,用于跟踪数组中的已连接用户:
class MPCManager: NSObject {
static let instance = MPCManager()
var devices: [Device] = []
...
我的设备class:
class Device: NSObject {
let peerID: MCPeerID
var session: MCSession?
var name: String
var state = MCSessionState.notConnected
var lastMessageReceived: Message?
...
}
当 MultiPeer 连接框架找到新的对等点时,MPCManager 正在将新设备附加到阵列。我已经在调试器中确认了这一点。当我尝试在列表中显示设备时出现问题。这是我正在使用的代码:
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)
}
}
}
}
当应用程序启动时,显示列表但它是空的。当我在 ForEach 执行中的视图代码中放置断点时,永远不会停止。当我将数组更改为硬编码的值列表时,它显示得很好。我也试过在我的视图中直接从静态实例引用数组,如下所示:
ForEach(self.devices.identified(by: \.name)) { device in
Text(device.name)
}
仍然没有。我是 swift 的新手,所以我可能缺少一些简单的东西,但我只是没有看到它。有什么想法吗?
据我所知这里有几个问题。
首先,我建议您使用 MPCManager
:
import SwiftUI
import Combine
class MPCManager: NSObject, BindableObject {
var didChange = PassthroughSubject<Void, Never>()
var devices: [Device] = [] {
didSet {
self.didChange.send(())
}
}
}
然后,在您的 ContentView
中执行此操作:
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)
}
}
}
}
回答您的问题的主要困难是我无法 运行 您的代码。如果您可以将代码提炼成可能知道答案的人可以复制并粘贴到 Xcode.
中的内容,那么您的问题对其他人会更有用(并且更容易回答)更新
从 Xcode Beta 4 开始,identified(by:)
已被 List
和 ForEach
的特定初始值设定项取代,从 Xcode Beta 5 开始, BindableObject
已替换为 ObservableObject
,@ObjectBinding
已替换为 @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)
}
}
}
}