len*_*nny 6 swift swiftui combine observableobject
让 swiftUI 仍然基于嵌套观察对象进行更新的最佳方法是什么?
以下示例显示了我对嵌套观察对象的含义。球管理器的 balls 数组是一个已发布的属性,其中包含可观察对象的数组,每个对象本身都有一个已发布的属性(颜色字符串)。
不幸的是,当点击其中一个球时,它不会更新球的名称,也不会收到更新。那么我可能搞砸了在这种情况下联合收割机是如何工作的?
import SwiftUI
class Ball: Identifiable, ObservableObject {
let id: UUID
@Published var color: String
init(ofColor color: String) {
self.id = UUID()
self.color = color
}
}
class BallManager: ObservableObject {
@Published var balls: [Ball]
init() {
self.balls = []
}
}
struct Arena: View {
@StateObject var bm = BallManager()
var body: some View {
VStack(spacing: 20) {
ForEach(bm.balls) { ball in
Text(ball.color)
.onTapGesture {
changeBall(ball)
}
}
}
.onAppear(perform: createBalls)
.onReceive(bm.$balls, perform: {
print("ball update: \($0)")
})
}
func createBalls() {
for i in 1..<4 {
bm.balls.append(Ball(ofColor: "c\(i)"))
}
}
func changeBall(_ ball: Ball) {
ball.color = "cx"
}
}
Run Code Online (Sandbox Code Playgroud)
您只需创建一个BallView并观察它并从那里进行更改。你必须ObservableObject直接观察每一个
struct Arena: View {
@StateObject var bm = BallManager()
var body: some View {
VStack(spacing: 20) {
ForEach(bm.balls) { ball in
BallView(ball: ball)
}
}
.onAppear(perform: createBalls)
.onReceive(bm.$balls, perform: {
print("ball update: \($0)")
})
}
func createBalls() {
for i in 1..<4 {
bm.balls.append(Ball(ofColor: "c\(i)"))
}
}
}
struct BallView: View {
@ObservedObject var ball: Ball
var body: some View {
Text(ball.color)
.onTapGesture {
changeBall(ball)
}
}
func changeBall(_ ball: Ball) {
ball.color = "cx"
}
}
Run Code Online (Sandbox Code Playgroud)
Ball当数组中的aballs发生变化时,可以调用objectWillChange.send()更新ObservableObject.
以下内容应该适合您:
class BallManager: ObservableObject {
@Published var balls: [Ball] {
didSet { setCancellables() }
}
let ballPublisher = PassthroughSubject<Ball, Never>()
private var cancellables = [AnyCancellable]()
init() {
self.balls = []
}
private func setCancellables() {
cancellables = balls.map { ball in
ball.objectWillChange.sink { [weak self] in
guard let self = self else { return }
self.objectWillChange.send()
self.ballPublisher.send(ball)
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
并通过以下方式进行更改:
.onReceive(bm.ballPublisher) { ball in
print("ball update:", ball.id, ball.color)
}
Run Code Online (Sandbox Code Playgroud)
balls注意:如果传入的初始值并不总是空数组,则还应该调用setCancellables()init.
| 归档时间: |
|
| 查看次数: |
2662 次 |
| 最近记录: |