title: In SwiftUI, how to react to changes on "@Published vars" *outside* of a "View"
body: <p>Suppose I have the following <code>ObservableObject</code>, which generates a random String every second:</p>
  
  <pre><code>import SwiftUI
  
  class SomeObservable: ObservableObject {
  
      @Published var information: String = ""
  
      init() {
          Timer.scheduledTimer(
              timeInterval: 1.0,
              target: self,
              selector: #selector(updateInformation),
              userInfo: nil,
              repeats: true
          ).fire()
      }
  
      @objc func updateInformation() {
          information = String("RANDOM_INFO".shuffled().prefix(5))
      }
  }
  </code></pre>
  
  <p>And a <code>View</code>, which observes that:</p>
  
  <pre><code>struct SomeView: View {
  
      @ObservedObject var observable: SomeObservable
  
      var body: some View {
          Text(observable.information)
      }
  }
  </code></pre>
  
  <p>The above will work as expected.<br>
  The <code>View</code> redraws itself when the <code>ObservableObject</code> changes:</p>
  
  <p><a href="https://i.stack.imgur.com/FnUqC.gif" rel="noreferrer"><img src="https://i.stack.imgur.com/FnUqC.gif" alt="viewUpdate"></a></p>
  
  <h2><strong>Now for the question</strong>:</h2>
  
  <p>How could I do the same (say calling a function) in a "pure" <code>struct</code> that also observes the same <code>ObservableObject</code>? By "pure" I mean something that <strong>does not</strong> conform to <code>View</code>:</p>
  
  <pre><code>struct SomeStruct {
  
      @ObservedObject var observable: SomeObservable
  
      // How to call this function when "observable" changes?
      func doSomethingWhenObservableChanges() {
          print("Triggered!")
      }
  }
  </code></pre>
  
  <p>(It could also be a <code>class</code>, as long as it's able to react to the changes on  the observable.)</p>
  
  <p>It seems to be conceptually very easy, but I'm  clearly missing something.</p>
  
  <p>(Note: I'm using Xcode 11, beta 6.)</p>
  
  <hr>
  
  <h2>Update (for future readers) (paste in a Playground)</h2>
  
  <p>Here is a possible solution, based on the awesome answer provided by @Fabian:</p>
  
  <pre><code>import SwiftUI
  import Combine
  import PlaygroundSupport
  
  class SomeObservable: ObservableObject {
  
      @Published var information: String = "" // Will be automagically consumed by `Views`.
  
      let updatePublisher = PassthroughSubject&lt;Void, Never&gt;() // Can be consumed by other classes / objects.
  
      // Added here only to test the whole thing.
      var someObserverClass: SomeObserverClass?
  
      init() {
          // Randomly change the information each second.
          Timer.scheduledTimer(
              timeInterval: 1.0,
              target: self,
              selector: #selector(updateInformation),
              userInfo: nil,
              repeats: true
          ).fire()    }
  
      @objc func updateInformation() {
          // For testing purposes only.
          if someObserverClass == nil { someObserverClass = SomeObserverClass(observable: self) }
  
          // `Views` will detect this right away.
          information = String("RANDOM_INFO".shuffled().prefix(5))
  
          // "Manually" sending updates, so other classes / objects can be notified.
          updatePublisher.send()
      }
  }
  
  class SomeObserverClass {
  
      @ObservedObject var observable: SomeObservable
  
      // More on AnyCancellable on: apple-reference-documentation://hs-NDfw7su
      var cancellable: AnyCancellable?
  
      init(observable: SomeObservable) {
          self.observable = observable
  
          // `sink`: Attaches a subscriber with closure-based behavior.
          cancellable = observable.updatePublisher
              .print() // Prints all publishing events.
              .sink(receiveValue: { [weak self] _ in
              guard let self = self else { return }
              self.doSomethingWhenObservableChanges()
          })
      }
  
      func doSomethingWhenObservableChanges() {
          print(observable.information)
      }
  }
  
  let observable = SomeObservable()
  
  struct SomeObserverView: View {
      @ObservedObject var observable: SomeObservable
      var body: some View {
          Text(observable.information)
      }
  }
  PlaygroundPage.current.setLiveView(SomeObserverView(observable: observable))
  </code></pre>
  
  <blockquote>
    <p>Result</p>
  </blockquote>
  
  <p><a href="https://i.stack.imgur.com/wFZP6.gif" rel="noreferrer"><img src="https://i.stack.imgur.com/wFZP6.gif" alt="result"></a></p>
  
  <p>(Note: it's necessary to run the app in order to check the console output.)</p>