Search code examples
swiftdictionarysubscriptionassigncombine

Setting up a combine publisher in swift using map


iOS 13, Swift 5.x

I am trying to get the syntax right on a combine subscription/publisher. I got a working example and I have tried to copy it, but I missing something; and I cannot see the wood for the trees. Here is my code.

import Foundation
import Combine

class SwiftUIViewCModel: ObservableObject {
  @Published var state : SwiftUIViewCModelState = .page1

  static let shared = SwiftUIViewCModel()

  private var stateUpdatingSubscriber: AnyCancellable?

  init() {
    self.stateUpdatingSubscriber = nil
    self.stateUpdatingSubscriber = SwiftUIViewCModel.shared.$state
      .map(modelCTomodelD(modelState:))
      .receive(on: RunLoop.main)
      .assign(to: \.state, on: self)
  

  }

 private func modelCTomodelD(modelState: SwiftUIViewCModelState) -> SwiftUIViewEModelState {
    switch modelState {
      case .page1:
      return .page1
    case .page2:
      return .page2
    default:
      break
 }
}

}

enum SwiftUIViewEModelState {
 case page1
 case page2
}

enum SwiftUIViewCModelState {
 case page1
 case page2
}

I am getting a syntax error on the compile, but I don't understand what exactly I need to do to fix it.

Cannot convert value of type '(SwiftUIViewCModelState) -> SwiftUIViewEModelState' to expected argument type 'KeyPath<Published.Publisher.Output, SwiftUIViewCModelState>' (aka 'KeyPath<SwiftUIViewCModelState, SwiftUIViewCModelState>')

How do I get the format it needs here into this code?

Thanks


Solution

  • I'm not really sure what the purpose of this code is.

    The error you're getting is that self.state is of type SwiftUIViewCModelState, but the value was converted to a SwiftUIViewEModelState via the map operator. The last step (.assign(to: \.state, on: self)) tries to save this new value back to the original self.state var, but it can't, because it's now a different type.

    I'm also not sure why you'd want to have a publisher/subscriber chain to modify a variable and save it back to itself?

    One way to make the code compile is to add a new variable, var state2: SwiftUIViewEModelState, and then change the .assign line to .assign(to: \.state2, on: self). This will create a subscription chain that uses the state var as the publisher, changes its type via map, and then saves the modified value to state2.