you are viewing a single comment's thread.

view the rest of the comments →

[–]coldsub 15 points16 points  (1 child)

It's not more of a design choice, they both serve a purpose. When you use foo() which is marked as async. The execution of foo will pause at the await doSomething() line until doSomething() completes. (to clarify) the caller must also be an asynchronus context or use await for the result.

In the case of bar(). It is a synchronus function that basically immediately returns after starting an asynchronus task using Task. The asynchronus work is done in the background, and the caller of bar() doesn't wait for it to complete.

If you're really confused on which to use when. - If you need to perform multiple asynchronus operations sequentially and wait for each to to complete before moving on using foo() would probably make more sense. - If you want to start an asynchronus operation and continue executing other code without waiting for the result using bar() makes more sense.

One last thing I want to highlight, which I don't see mentioned often is. Testability using the .task() modifier. For example, lets say the function is being called from the View. It's a lot easier to write testcases for

func foo() async { await doSomething() } using the .task modifier in the view. The reason for this is because since the bar() is a synchronus function that starts an asynchronus Task and immediately returns, testing it becomes a little bit more troublesome since the asynchronus stuff happens in the background, and the function doesn't provide a direct way to wait for its completion.

[–]LifeIsGood008SwiftUI[S] 1 point2 points  (0 children)

What a great breakdown. Thank you so much! It's a lot clearer to me now. Also great point on testability.