SwiftUI 视图更新

Posted

技术标签:

【中文标题】SwiftUI 视图更新【英文标题】:SwiftUI View updating 【发布时间】:2021-08-09 10:43:46 【问题描述】:

我有:

class Exercise: ObservableObject 
  @Published var currentSet: Int = 1
  func start()  somehow changing currentSet 


class ExerciseProgram: ObservableObject 
  @Published var currentExercise: Exercise? = nil

  func start()  ...self.currentExercise = self.exercises[exerciseIndex + 1]... 


struct Neck: View 
  @ObservedObject var program: ExerciseProgram = ExerciseProgram(exercises: neckExercises)

  var body: some View 
    Text(\(self.program.currentExercise!.currentSet))
  

问题是我的View只有在ExerciseProgram的currentExercise改变时才更新,而currentExercise本身有currentSet属性,当它改变时我的view没有更新。原则上,我理解为什么我们完全按照它的工作方式工作的逻辑:我指定了当 currentExercise 更改时应该更新视图,但我没有说当 currentExercise 实体的属性发生更改时应该更新视图。所以我不明白该怎么做。而且我不能将运动更改为结构

【问题讨论】:

this SO answer处理嵌套的可观察对象,可能对您有用。 ***.com/questions/58406287/… 以下文章建议避免这种结构并重新审视大局。 rhonabwy.com/2021/02/13/nested-observable-objects-in-swiftui 【参考方案1】:

您只需要在适当的级别观察对象即可。

每个@Published 仅在对象整体发生变化时触发刷新。

在您的示例中,如果您替换数组或添加/删除对象,数组将会改变。

import SwiftUI
struct ExerciseProgramView: View 
    //At this level you will see the entire program
    @StateObject var program: ExerciseProgram = ExerciseProgram()
    
    var body: some View 
        VStack
            if program.currentExercise != nil
                ExerciseView(exercise: program.currentExercise!)
            else
                Text("Ready?")
            
            Spacer()
            HStack
                if program.currentExercise == nil
                    Button("start program", action: 
                        program.start()
                    )
                else
                    Button("stop", action: 
                        program.stop()
                    )
                    Button("next", action: 
                        program.next()
                    )
                
                
            
        
    

struct ExerciseView: View 
    //At this level you will see the changes for the exercise
    @ObservedObject var exercise: Exercise
    
    var body: some View 
        VStack
            Text("\(exercise.name)")
            Text("\(exercise.currentSet)")
            if exercise.timer == nil
                Button("start exercise", action: 
                    exercise.start()
                )
            else
                Button("stop exercise", action: 
                    exercise.stop()
                )
            
        .onDisappear(perform: 
            exercise.stop()
        )
    


struct ExerciseProgramView_Previews: PreviewProvider 
    static var previews: some View 
        ExerciseProgramView()
    

class Exercise: ObservableObject, Identifiable 
    let id: UUID = UUID()
    let name: String
    @Published var currentSet: Int = 1
    var timer : Timer?
    init(name: String)
        self.name = name
    
    func start() 
        timer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true, block:  timer in
            
            self.currentSet += 1
            
            if self.currentSet >= 10
                timer.invalidate()
                self.timer = nil
            
            
        )
    
    
    func stop()
        timer?.invalidate()
        timer = nil
    


class ExerciseProgram: ObservableObject 
    @Published var currentExercise: Exercise? = nil
    @Published var exercises: [Exercise] = [Exercise(name: "neck"), Exercise(name: "arm"), Exercise(name: "leg"), Exercise(name: "abs")]
    @Published var exerciseIndex: Int = 0
    func start() 
        self.currentExercise = self.exercises[exerciseIndex]
    
    
    func next()
        if exerciseIndex < exercises.count
            self.exerciseIndex += 1
        else
            self.exerciseIndex = 0
        
        start()
    
    
    func stop()
        exerciseIndex = 0
        currentExercise = nil
    

另外,请注意ObservableObjects 是如何被初始化的。

@StateObject 用于必须在 View 中初始化对象时使用

@ObservedObject 用于将ObservableObject 传递给子View,但该对象是在class 中创建的,特别是 class ExerciseProgram

https://developer.apple.com/documentation/swiftui/managing-model-data-in-your-app

【讨论】:

以上是关于SwiftUI 视图更新的主要内容,如果未能解决你的问题,请参考以下文章

值更改时如何在 UIKit 中更新 SwiftUI 视图?

SwiftUI,为啥部分视图没有刷新? @State 变量未更新

SwiftUI 和 UIGraphicsImageRenderer 没有快照更新的视图

SwiftUI 视图更新

SwiftUI - 更新@State 不会改变视图

如何使用 SwiftUI 更新不同的视图?