当 Class 发生变化时,如何在 Class B 上执行函数?

How do I execute a function on ClassB when something changes in ClassA?

我有一个用 SwiftUI 编写的游戏,有两个 classes,一个 Game class 来管理游戏,还有一个 ScoreStore class 来管理一系列高分。当前,当用户按下按钮(显示在 ContentView 结构中)开始新游戏时,游戏的分数会被存储(通过 ScoreStore 上的函数)。我想在游戏达到某个状态(这里认为是某个分数)时保存分数。

Game 和 ScoreStore 都是 ObservableObjects,并且具有 @Published 属性作为 @EnvironmentObjects 提供给 ContentView。在 Game 中,score 不是 @Published 因为它是计算的 属性.

class Game: ObservableObject, Codable {
    
    var deck: [Card] = []
    
    @Published var piles: [[Card]] = [[],[],[],[]] 

    var score: Int {
        let fullDeckCount = 52
        var cardsOnThePiles = 0
        for pile in piles {
            cardsOnThePiles += pile.count
        }
        return fullDeckCount - deck.count - cardsOnThePiles
    }

class ScoresStore: Codable, ObservableObject, Identifiable {
    
    @Published var highScores: [Score] = []
    
    func addScore(newScore: Int, date: Date = Date()) {
        // Do things to add the score to the array
}
        
struct ContentView: View {
    @EnvironmentObject var game: Game
    @EnvironmentObject var scores: ScoresStore

func saveScore() {
        scores.addScore(newScore: game.score)
    }
    
var body: some View {
    Button(action: { saveScore }) {
        Text("New Game?")
    }
}

我查看了其答案通过 @State 属性 绑定的问题,但在这种情况下,属性 我正在“观察”的是游戏(而不是 ContentView)。

提前致谢!

您需要一个 PassThroughSubject 来允许您的视图在 @Published 值更改时被触发以执行某些操作。然后,在您看来,您使用 .onReceive 来触发您的函数。

import SwiftUI
import Combine

struct ContentView: View {
    @EnvironmentObject var game: Game
    @EnvironmentObject var scores: ScoresStore
    
    func saveScore() {
        scores.addScore(newScore: game.score)
    }
    
    var body: some View {
        Button(action: { saveScore }) {
            Text("New Game?")
        }
        .onReceive(game.objectDidChange, perform: { _ in
            //Do something here
        })
        .onReceive(scores.objectDidChange, perform: { _ in
            //Do something here
        })
    }
}

final class Game: NSObject, ObservableObject, Codable {
    
    let objectDidChange = PassthroughSubject<Void, Never>()
    
    var deck: [Card] = []
    
    @Published var piles: [[Card]] = [[],[],[],[]] {
        didSet {
            self.objectDidChange.send()
        }
    }
    
    var score: Int {...}
}

final class ScoresStore: NSObject, Codable, ObservableObject, Identifiable {
    
    let objectDidChange = PassthroughSubject<Void, Never>()
    
    @Published var highScores: [Score] = [] {
        didSet {
            self.objectDidChange.send()
        }
    }
    
    func addScore(newScore: Int, date: Date = Date()) {
        // Do things to add the score to the array
    }
}

每次Game.pilesScoreStore.highScores更新,您都会收到通知到您视图中的.onReceive,以便您进行处理。我怀疑您也想以这种方式跟踪游戏得分,并触发该更改。然后您可以测试您想要的任何内容并执行您想要的任何操作。您还会注意到我是在 didSet 上做的。您还会将其视为 objectWillSet 放入变量的 willSet 中。两者都有效,但 willSet 在实际更新之前发送触发器,而 didSet 在实际更新之后发送。这可能没有什么不同,但我过去曾有过这个问题。最后,我在顶部导入了 Combine,但我在一个文件中完成了这些。无论您在哪里定义 passThroughSubject,您都需要导入 Combine。视图实际上并不需要导入它。祝你好运。