Реагировать на событие (не констатировать!) - PullRequest
0 голосов
/ 20 июня 2020

У меня есть представление, которое наблюдает за моделью (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
    }
}

Теперь я хочу установить переменную состояния description на "", когда step изменяется с .third на .first, но не если он изменится с .second на .first. Как я могу этого добиться?

Ответы [ 2 ]

0 голосов
/ 20 июня 2020
Обертка свойств

@Published уже предоставляет вам Published.Publisher, доступный через префикс $, который будет публиковать sh каждый раз, когда значение изменяется.

Вы можете подписаться на него, чтобы установите свойство description, но вам придется переместить весь этот logi c в модель представления ObservableObject, так как вы не можете изменить представление.

Значение, которое вы получите в подписке, будет значение, которое будет установлено для свойства шага - просто до значение свойства фактически изменится, поэтому вы можете сравнить новое значение в подписке с существующим значением свойства.

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 в модель представления) состоит в создании издателя, который выдает только значение когда он переключается с .third на .first, а затем подписывается на него в .onReceive в представлении, чтобы установить 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 = ""
         }
   }
}
0 голосов
/ 20 июня 2020

Чтобы добиться желаемого (реагировать на события), попробуйте что-то вроде этого тестового кода. Ключ должен использовать .onReceive (...)

Edit (незначительное исправление):

import SwiftUI

enum Step {
case first
case second
case third

var toString : String {
  switch self {
  case .first: return "first"
  case .second: return "second"
  case .third: return "third"
  }
}
}

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

struct ContentView: View {

@ObservedObject var postModel = PostModel()
@State var description: String = Step.first.toString

var body: some View {
    VStack (spacing: 30) {
        Text("current step \(self.postModel.prevStep.toString)")
        Button(action: {
            switch self.postModel.step {
            case .first:  self.postModel.step = .second
            case .second: self.postModel.step = .third
            case .third:  self.postModel.step = .first
            }
        }){
            Text("change to next step")
            }.padding(30).border(Color.blue)

        Text("description: \(description)")
            .onReceive(postModel.$step) { thisStep in
                if self.postModel.prevStep == .third && thisStep == .first {
                    self.description = ""
                } else {
                    self.description = thisStep.toString
                }
                self.postModel.prevStep = thisStep
        }
    }
}
}
...