SwiftUI ForEach 在数组更改时不迭代。列表为空并且 ForEach 确实运行

ins*_*hex 1 swift swiftui

我正在尝试将 MultiPeer Connectivity 框架与 swift ui 一起使用,并且在我看来使用 ForEach 时遇到了问题。我有一个单例,用于跟踪数组中的连接用户:

class MPCManager: NSObject {
    static let instance = MPCManager()
    var devices: [Device] = []
...
Run Code Online (Sandbox Code Playgroud)

我的设备类:

class Device: NSObject {
    let peerID: MCPeerID
    var session: MCSession?
    var name: String
    var state = MCSessionState.notConnected
    var lastMessageReceived: Message?
...
}
Run Code Online (Sandbox Code Playgroud)

当 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)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

当应用程序启动时,列表会显示,但它是空的。当我在 ForEach 执行中的视图代码中放置断点时,它永远不会停止。当我将数组更改为硬编码的值列表时,它显示得很好。我还尝试在我的视图中直接从静态实例引用数组,如下所示:

ForEach(self.devices.identified(by: \.name)) { device in
    Text(device.name)
}
Run Code Online (Sandbox Code Playgroud)

依然没有。我对 swift 很陌生,所以可能有一些我遗漏的简单的东西,但我只是没有看到它。有任何想法吗?

gra*_*ell 5

据我所知,这里有几个问题。

首先,我建议你试试这个MPCManager

import SwiftUI
import Combine

class MPCManager: NSObject, BindableObject {
    var didChange = PassthroughSubject<Void, Never>()

    var devices: [Device] = [] {
        didSet {
            self.didChange.send(())
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后,在您的 中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)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

回答您的问题的主要困难是我无法运行您的代码。如果您可以将代码提炼为可能知道答案的人只需将其复制并粘贴到 Xcode 中的内容,那么您的问题对其他人会更有用(并且更容易回答)。

更新

作为Xcode的贝塔4的,identified(by:)已被取代的特定初始化ListForEach,并作为Xcode的贝塔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()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
struct ContentView : View {
    @ObservedObject var manager: MPCManager = MPCManager()

    var body: some View {
        List {
            ForEach(self.manager.devices, id: \.name) { device in
                Text(device.name)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

  • 我想没有给出编译示例是我投反对票的原因。我不太确定如何用一小段代码重现该问题。我的问题是变更检测问题。创建视图后正在填充数组,并且没有任何信号表明视图需要刷新。使管理器符合 BindableObject 效果非常好。谢谢。 (2认同)