/*:#localized(key: "MainActorRun")
 # `MainActor.run`: a one-off hop onto main

 Marking a whole type `@MainActor` is the right call when the type's job is the
 UI. But sometimes you are deep in background work, a big calculation, a parse, a
 batch import, and only *one small piece* needs the main actor: the moment you
 update the display. Moving the whole task onto main just for that would waste the
 main thread.

 `MainActor.run { }` runs a single closure on the main actor, waits for it, and
 hands its result back. Here we do heavy work on a background thread, then hop just
 the display update onto main:
 */
//#-hidden-code
import Foundation
import PlaygroundSupport

PlaygroundPage.current.needsIndefiniteExecution = true

// Read the thread through a synchronous helper, so it is safe to call from a task.
func runningOnMainThread() -> Bool {
    Thread.isMainThread
}

@MainActor
final class BalanceDisplay {
    private(set) var balance = 0

    func deposit(_ amount: Int) {
        balance += amount
        print("Deposited \(amount), balance now \(balance). On main thread? \(runningOnMainThread())")
    }
}

let display = BalanceDisplay()
//#-end-hidden-code
//#-editable-code
Task.detached {
    // Pure background work (imagine a big calculation), off the main thread.
    print("Adding up the deposits. On main thread? \(runningOnMainThread())")
    let total = (1...50).reduce(0, +)

    // Hop just the display update onto the main actor, and hand a value back.
    let shown = await MainActor.run {
        display.deposit(total)
        return display.balance
    }

    print("Back off the main actor, the display reads \(shown). On main thread? \(runningOnMainThread())")
    PlaygroundPage.current.finishExecution()
}
//#-end-editable-code
/*:#localized(key: "MainActorRunNotice")
 The first line prints `false`: the addition ran off the main thread, where heavy
 work belongs. Inside `MainActor.run` the deposit prints `true`: that one closure,
 and only that closure, ran on the main actor. The value it returned came back
 across the hop, so `shown` is usable off main again.

 This is the modern echo of "do the heavy lifting off-main, then
 `DispatchQueue.main.async` to update the label", except it is one expression, it
 can return a value, and the compiler guarantees the closure really runs on main.

 * callout(Try it): Add a second `display.deposit(25)` inside the same
 `MainActor.run` block. Both updates happen in a *single* hop onto main. Without
 `MainActor.run` you would `await` each one separately, hopping back and forth for
 every line.

 ## Running a whole task on main
 
 `MainActor.run` hops a single closure. When you want an *entire* task to run on
 the main actor, from anywhere, even deep in background code, start it with
 `Task { @MainActor in }`:

 ```swift
 Task { @MainActor in
     display.deposit(25)   // already on the main actor, so no await
     display.deposit(25)
 }
 ```

 Everything inside runs on the main actor, so the `await`s you needed on the
 previous page simply disappear.

 [Previous](@previous)  |  page 4 of 11  |  [Next: Marking Just a Function or Property](@next)
 */
