title: SwiftUI call function on variable change
body: <p>I am trying to convert a view of my watchOS App to Swift UI. 
  I wanted to port the volume control that can be found in watchKit to SwiftUI with custom controls. In the image below you can see the current state of the view. </p>
  
  <p>The volume control changes the progress of the ring according to current state <code>volume</code> and the <code>volume</code> also changes when I turn the Digital Crown. 
  Without SwiftUI it was possible to call a function on the turn of the crown. This has changed and the system only allows me to bind a variable to it. </p>
  
  <p>What I want to do know is to bind a variable and call a function on every change of that variable. Because the normal Digital Crown behavior does not fulfill my needs. </p>
  
  <p>One thing that works, but is far from perfect is: </p>
  
  <pre class="lang-swift prettyprint-override"><code>.digitalCrownRotation($crownAccumulator, from: -100.0, through: 100.0, by: 1, sensitivity: .low, isContinuous: true, isHapticFeedbackEnabled: true)
  .onReceive(Just(self.crownAccumulator), perform: self.crownChanged(crownAccumulator:))
  </code></pre>
  
  <p>OnReceive will be called with every twist of the crown, but it will also be called with every other update to the view. </p>
  
  <p>So what I want is a pipeline like this: </p>
  
  <p>Crown rotates → <code>crownAccumulator</code> changes → Function called async → Function updates <code>volume</code> </p>
  
  <p>In the past I would have done this with a didSet, but this is no longer available </p>
  
  <p>Here the code of it: </p>
  
  <pre class="lang-swift prettyprint-override"><code>
      @ObservedObject var group: Group
      @State var animateSongTitle: Bool = false
  
      @State var songTitle: String = "Very long song title that should be scrolled"
      @State var artist: String = "Artist name"
  
  
      @State var volume: Int = 30
      @State var isMuted = false
      @State var crownAccumulator: CGFloat = 0.0
  
  
      var body: some View {
  
         VStack(alignment: .center) {
              TitleView(songTitle: $songTitle, artist: $artist)
              GroupControlButtons(
                  skipPreviousAction: skipPrevious,
                  skipNextAction: skipNext,
                  playPauseAction: playPause,
                  group: group)
  
              ZStack {
                  HStack {
                      VolumeControl(
                          volumeLevel: $volume,
                          isMuted: $isMuted,
                          muteAction: self.muteButtonPressed)
                              .frame(minWidth: 40.0, idealWidth: 55, minHeight: 40.0, idealHeight: 55, alignment: .center)
                              .aspectRatio(1.0, contentMode: .fit)
  
  
                  }
              }
  
  
          }
          .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .topLeading)
          .edgesIgnoringSafeArea([.bottom])
          .focusable(true)
  //        .digitalCrownRotation($crownAccumulator)
          .digitalCrownRotation($crownAccumulator, from: -100.0, through: 100.0, by: 1, sensitivity: .low, isContinuous: true, isHapticFeedbackEnabled: true)
          .onReceive(Just(self.crownAccumulator), perform: self.crownChanged(crownAccumulator:))
  
  
  </code></pre>
  
  <p>Here's the current view: <br> 
  <a href="https://i.stack.imgur.com/JdDWX.png" rel="noreferrer"><img src="https://i.stack.imgur.com/JdDWX.png" alt="Current View"></a> </p>