首页 > 解决方案 > 对事件做出反应(而不是陈述!)

问题描述

我有一个观察模型(postModel)的视图:

struct PostView: View {
    @ObservedObject var postModel: PostModel
    @State var description: String = ""
}

class PostModel: ObservableObject {

    @Published var step: Step = .first   

    enum Step {
        case first
        case second
        case third
    }
}

现在我想将状态变量设置为何时从 to 更改description,但不是如果它从to更改。我怎样才能做到这一点?""step.third.first.second.first

标签: iosswiftui

解决方案


@Published属性包装器已经为您提供了一个Published.Publisher, 可通过$前缀访问,该前缀将在值更改时发布。

您可以订阅它以设置description属性,但您必须将整个逻辑移动到 ObservableObject 视图模型中,因为您不能改变视图。

您将在订阅中收到的值将是 step 属性将设置为的值 - 就属性值实际更改之前,因此您可以将订阅中的新值与属性的现有值进行比较。

class PostModel: ObservableObject {
    @Published var step: Step = .first   
    @Published var description: String = ""

    private var cancellables = Set<AnyCancellable>()

    init() {
       self.$step.sink { nextStep in
          if nextStep == .first && self.step == .third {
             self.description = ""
          }
       }.store(in: &cancellables)
    }

    enum Step { case first, second, third }
}

struct PostView: View {
    @ObservedObject var postModel: PostModel

    var body: some Body {
       Text(postModel.description)
    }
}

为了完整起见另一种方法(如果您不想移动description到视图模型中)是创建一个发布者,该发布者仅在从.thirdto切换时发出一个值.first,然后.onReceive在 View 中订阅它以设置description

class PostModel: ObservableObject {
   @Published var step: Step = .first

   var newCycle: AnyPublisher<(), Never> {
      $step.compactMap { $0 == .first && self.step == .third ? () : nil }
           .eraseToAnyPublisher()
   }

   enum Step { case first, second, third }
}

然后,在PostView

struct PostView: View {
   @ObservedObject var postModel: PostModel
   @State var description: String = ""

   var body: some Body {
      VStack() {
         Text(description)
      }
      .onReceive(postModel.newCycle) {
            self.description = ""
         }
   }
}

推荐阅读