title: `Task` blocks main thread when calling async function inside
body: <p>I have an <code>ObservableObject</code> class and a SwiftUI view. When a button is tapped, I create a <a href="https://developer.apple.com/documentation/swift/task" rel="noreferrer"><code>Task</code></a> and call <code>populate</code> (an async function) from within it. I thought this would execute <code>populate</code> on a background thread but instead the entire UI freezes. Here's my code:</p>
  <pre><code>class ViewModel: ObservableObject {
      @Published var items = [String]()
      func populate() async {
          var items = [String]()
          for i in 0 ..&lt; 4_000_000 { /// this usually takes a couple seconds
              items.append(&quot;\(i)&quot;)
          }
          self.items = items
      }
  }
  
  struct ContentView: View {
      @StateObject var model = ViewModel()
      @State var rotation = CGFloat(0)
  
      var body: some View {
          Button {
              Task {
                  await model.populate()
              }
          } label: {
              Color.blue
                  .frame(width: 300, height: 80)
                  .overlay(
                      Text(&quot;\(model.items.count)&quot;)
                          .foregroundColor(.white)
                  )
                  .rotationEffect(.degrees(rotation))
          }
          .onAppear { /// should be a continuous rotation effect
              withAnimation(.easeInOut(duration: 2).repeatForever()) {
                  rotation = 90
              }
          }
      }
  }
  </code></pre>
  <p>Result:</p>
  <img src="https://i.stack.imgur.com/TnDMi.gif" width="200" alt="Rotation animation freezes when the button is pressed">
  <p>The button stops moving, then suddenly snaps back when <code>populate</code> finishes.</p>
  <p>Weirdly, if I move the <code>Task</code> into <code>populate</code> itself and get rid of the <code>async</code>, the rotation animation doesn't stutter so I think the loop actually got executed in the background. However I now get a <code>Publishing changes from background threads is not allowed</code> warning.</p>
  <pre><code>func populate() {
      Task {
          var items = [String]()
          for i in 0 ..&lt; 4_000_000 {
              items.append(&quot;\(i)&quot;)
          }
          self.items = items /// Publishing changes from background threads is not allowed; make sure to publish values from the main thread (via operators like receive(on:)) on model updates.
      }
  }
  
  /// ...
  
  Button {
      model.populate()
  }
  </code></pre>
  <p>Result:</p>
  <img src="https://i.stack.imgur.com/kqkuK.gif" width="200" alt="Rotation animation continues even when the button is pressed">
  <p>How can I ensure my code gets executed on a background thread? I think this might have something to do with <code>MainActor</code> but I'm not sure.</p>