Swift 当ClassA中发生变化时,如何在ClassB上执行函数?

Swift 当ClassA中发生变化时,如何在ClassB上执行函数?,swift,swiftui,combine,Swift,Swiftui,Combine,我有一个用SwiftUI编写的游戏,有两个类,一个用于管理游戏的游戏类,一个用于管理一系列高分的ScoreStore类。当前,当用户按下按钮(显示在ContentView结构中)开始新游戏时,会存储游戏分数(通过ScoreStore上的函数)。我希望在游戏达到某个状态时保存分数(这里被认为是某个分数) Game和ScoreStore都是ObservieoObject,并具有可作为@EnvironmentObjects提供给ContentView的@Published属性。在游戏中,分数不会@Pu

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

Game和ScoreStore都是ObservieoObject,并具有可作为@EnvironmentObjects提供给ContentView的@Published属性。在游戏中,分数不会@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
    }

我看过一些问题,它们的答案通过@State属性引用绑定,但在本例中,我“观察”的属性是在游戏中(而不是ContentView)


提前谢谢

您需要一个
PassThroughSubject
,以便在
@发布的
值更改时触发视图执行某些操作。然后,在视图中,使用
.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
    }
}
导入快捷界面
进口联合收割机
结构ContentView:View{
@环境对象变量游戏:游戏
@环境对象变量分数:ScoresStore
func saveScore(){
scores.addScore(新闻核心:game.score)
}
var body:一些观点{
按钮(操作:{saveScore}){
文本(“新游戏?”)
}
.onReceive(game.objectDidChange,perform:{uu}in
//在这里做点什么
})
.onReceive(scores.objectDidChange,perform:{uu}in
//在这里做点什么
})
}
}
最后一类游戏:NSObject,ObservieObject,Codable{
让objectDidChange=PassthroughSubject()
变量组:[卡]=[]
@已发布的变量堆:[[Card]]=[]、[]、[]、[]、[]、[]{
迪塞特{
self.objectDidChange.send()
}
}
变量分数:Int{…}
}
最终类分数存储:NSObject、可编码、可观察对象、可识别{
让objectDidChange=PassthroughSubject()
@已发布变量高分:[分数]=[]{
迪塞特{
self.objectDidChange.send()
}
}
func addScore(newScore:Int,date:date=date()){
//采取措施将分数添加到数组中
}
}
每次
Game.piles
ScoreStore.highScores
更新时,您都会收到视图中
.onReceive
的通知,这样您就可以处理它了。我想你也会希望通过这种方式来跟踪比赛的得分,并触发这种变化。然后,您可以测试您想要的任何内容,并执行您想要的任何操作。您还将注意到,我是在一个
didSet
上这样做的。您还可以将其视为放置在变量上的
willSet
中的
objectWillSet
。两者都可以工作,但是
将在实际更新之前发送触发器,而
didSet
在实际更新之后发送触发器。这可能不会有什么不同,但我在过去就有过这个问题。最后,我在顶部导入了
Combine
,但我在一个文件中完成了这些操作。无论您在何处定义
passThroughSubject
,都需要导入
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?")
    }
}
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
    }
}