多级子级上的 SwiftUI 更改已发布的对象更改

jmr*_*eda 3 swift swiftui

我有一个 ObservedObject AppStatus 类,它内部有多个 Published 类。如果我只在孩子方面有水平,一切都会很好。

当我有一个 RecordingTimeManager 类,其中有另一个变量(2 级子级)时,问题就出现了。当我按下按钮时,变量 maxRecordingTime 正在正确更改,它会打印“15 15Seconds”,但 foregroundColor 不会触发更改。我不确定这是否是 SwiftUI 错误,或者我应该以另一种方式构建关系:

// 应用程序状态

// Recording
@Published var recordingTimeManager: RecordingTimeManager = RecordingTimeManager()
Run Code Online (Sandbox Code Playgroud)

// 录音时间管理器

class RecordingTimeManager {
    @Published var maxRecordingTime: TimeSeletedTime = .sixteenSeconds
...
Run Code Online (Sandbox Code Playgroud)

// 需要根据 maxRecordingTime 更改更改不透明度的 SwiftUI 组件(.foregroundColor 未更改)

Button {
    appStatus.recordingTimeManager.maxRecordingTime = .fifteenSeconds
    print("15 \(appStatus.recordingTimeManager.maxRecordingTime)")
} label: {
    Text("15")
        .font(Font.custom("BwGradual-Bold", size: 15))
        .foregroundColor(appStatus.recordingTimeManager.maxRecordingTime == .fifteenSeconds ? CLAPSOFFWHITE : TRIBESGREY)
}
Run Code Online (Sandbox Code Playgroud)

非常感谢,

New*_*Dev 11

可观察对象不仅仅在具有多个级别的类时才起作用。@Published当属性发生更改时,属性包装器会通知视图,但因为此属性是一种引用class类型,所以当您更改其属性之一时,它实际上不会更改。换句话说,引用保持不变。

内部@Published不会做任何事情,因为没有任何东西直接观察它(即使RecordingTimeManager符合ObservableObject

因此,您需要创建RecordingTimeManager一个值类型 - a struct

struct RecordingTimeManager {
   var maxRecordingTime: TimeSeletedTime = .sixteenSeconds
}
Run Code Online (Sandbox Code Playgroud)

或者,如果它必须是 a class(可能因为它有一些内部状态和生命周期),那么您可以创建一个直接观察它的内部视图。

首先,它必须是ObservableObject

class RecordingTimeManager: ObservableObject {
    @Published var maxRecordingTime: TimeSeletedTime = .sixteenSeconds
Run Code Online (Sandbox Code Playgroud)

然后创建一个观察它的视图(可以是私有内部视图):

struct MainView: View {
   @StateObject var appStatus: AppStatus = .init()

   private struct InnerView: View {
      @ObservedObject var recordingManager: RecordingTimeManager

      var body: some View {
         Button {
           recordingManager.maxRecordingTime = .fifteenSeconds
         } label: {
           Text("15")
             .font(Font.custom("BwGradual-Bold", size: 15))
             .foregroundColor(
                 recordingManager.maxRecordingTime == .fifteenSeconds 
                    ? CLAPSOFFWHITE : TRIBESGREY)
         }
      }
   }

   var body: some View {

      InnerView(recordingManager: appStatus.recordingTimeManager)
   }
}
Run Code Online (Sandbox Code Playgroud)