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

时间:2019-07-14 00:18:35

标签: swift swiftui

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

class MPCManager: NSObject {
    static let instance = MPCManager()
    var devices: [Device] = []
...

我的设备类:

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)
}

什么都没有。我是新手,所以可能有些容易遗失的东西,但我只是看不到。有什么想法吗?

2 个答案:

答案 0 :(得分:1)

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

首先,我建议您尝试使用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中的内容,那么您的问题对其他人将更有用(并且更容易回答)。

答案 1 :(得分:0)

这是您可以运行的示例。当您点击一行时,假设要切换其选择。我已经用ObservableObject等添加了内容,直到脸色发青并且无法更新它。我觉得有一个简单,明显的解决方案,但我没有看到。

class Layer: NSObject, Identifiable, ObservableObject {
let didChange = PassthroughSubject<Void, Never>()

var id = UUID()
var name: String
var apiClass: String
var selected = false {
    willSet {
        didChange.send()
    }
}

static func == (lhs: Layer, rhs: Layer) -> Bool {
    lhs.id == rhs.id
}

init(name: String, apiClass: String, selected: Bool = false) {
    self.name = name
    self.apiClass = apiClass
    self.selected = selected
}
}

class Manager: NSObject, ObservableObject {
let didChange = PassthroughSubject<Void, Never>()
@Published var layers = [
    Layer(name: "All Assets", apiClass: "asset"),
    Layer(name: "Stopped", apiClass: "asset", selected: true),
    Layer(name: "Orders", apiClass: "orders")
]

func toggle(layer: Layer) {
    layer.selected = !layer.selected
    didChange.send()
}
}

struct ContentView: View {
@ObservedObject var manager = Manager()

var body: some View {
    List {
        ForEach(manager.layers) { layer in
            HStack {
                Image(systemName:
                    layer.selected ? "checkmark.circle.fill" : "circle"
                )
                Text(layer.name)
            }
            .onTapGesture {
                self.manager.toggle(layer: layer)
            }
            .padding()
        }
    }
}
}

我觉得您实际上不需要真正拥有PassthroughSubject和send(),但是即使那样也不起作用。