← Study Hub

06 · @MainActor

"이미 메인이면 안 멈춘다"가 과장인 이유 — hop과 suspend의 구분
진행률
0 / 0 완료

← 문항 인덱스

면접 질문
  1. @MainActor 함수를 이미 main actor에서 호출하면 await에서 실제로 suspend 하나요?
  2. 백그라운드 작업 중 일부만 메인에서 실행해야 할 때의 선택지는?

답변 ① — hop은 없지만, suspend는 callee에 달렸다 🔥 핵심

이 질문은 두 가지를 구분해야 제대로 답이 됩니다.

그러므로 "이미 메인이니 무조건 안 멈춘다"는 과장입니다. 정확히는 callee가 아무것도 기다리지 않고 동기적으로 끝날 때만 실제 suspend가 없습니다. await 키워드가 여전히 필요한 이유도 여기에 있습니다 — "여기서 멈추고 재진입이 일어날 수도 있다"는 표시이기 때문입니다.

⚠️ 주의

이 구분을 놓치면 "메인이니까 상태가 안 바뀐다"고 가정한 코드를 쓰게 됩니다. suspend가 일어나면 main actor도 재진입되므로, await 전후로 self의 상태가 바뀌어 있을 수 있습니다(01번 문항과 같은 함정).

hop은 없지만 suspend는 일어날 수 있다 (Swift)
@MainActor
final class ViewModel {
    var items: [Item] = []

    func onTap() async {
        await refresh()    // 같은 main actor → hop 없음(항상 보장)
                           // 단, refresh 안에서 진짜 기다리면 여기서 suspend
                           // → 그 틈에 다른 main-actor 작업이 끼어들 수 있다(재진입)
    }

    func refresh() async {
        // 이 줄까지는 동기로 진행 → 위 await는 아직 실제 suspend가 아니다
        let data = await api.load()   // ← 진짜 suspension point: 여기서 멈춘다
        items = data
    }
}

답변 ② — 좁게 격리하거나, 그 구간만 메인으로 올린다

백그라운드 작업 중 일부만 메인에서 실행하는 선택지는 셋입니다.

피해야 할 것은 타입 전체를 통째로 @MainActor로 덮는 것입니다. 무거운 계산까지 메인에서 돌아 화면이 버벅입니다. 원칙은 "무거운 일은 백그라운드, 화면을 실제로 바꾸는 짧은 순간만 메인"입니다.

⚠️ 주의

MainActor.assumeIsolated는 컴파일 타임 보장이 아니라 런타임 어서션입니다. 실제로 메인이 아니면 크래시합니다. 편의로 쓰다 사고가 나므로 명시적 격리를 우선하세요. app 타깃이라면 Swift 6.2의 Default Actor Isolation = MainActor가 더 나은 선택입니다.

백그라운드에서 일하고 UI만 잠깐 메인에서 (Swift)
func work() async {
    let processed = await heavyCompute()              // 백그라운드에서 무거운 계산

    await MainActor.run { view.update(processed) }    // 이 구간만 메인 무대
}

// 또는 — UI 갱신 함수 쪽에 좁게 격리를 선언(더 권장)
@MainActor
func apply(_ data: [Item]) { view.update(data) }

func work2() async {
    let processed = await heavyCompute()   // 백그라운드
    await apply(processed)                 // 호출 시 자동으로 메인으로 hop
}

쉽게 이해하기

@MainActor"이 일은 꼭 메인 무대 위에서 해"라는 뜻이에요.

(질문 ①) 내가 이미 메인 무대에 서 있으면, 다른 일을 부를 때 무대를 옮길 필요가 없어요. 그게 "hop이 없다"는 말입니다. 하지만 그 일이 중간에 "택배 올 때까지 기다려" 같은 걸 만나면, 그동안 나는 잠깐 무대를 비웁니다. 그 틈에 다른 배우가 올라올 수 있죠. 그러니 "메인에 있으니 절대 안 멈춘다"고 단정하면 안 되고, 그 일이 뭔가를 기다리느냐에 달렸다고 답해야 맞아요.

(질문 ②) 무거운 일까지 메인 무대에서 하면 무대가 꽉 차서 화면이 버벅여요. 그래서 계산 같은 건 뒷무대(백그라운드)에서 하고, 화면을 실제로 바꾸는 짧은 순간만 잠깐 메인 무대에 올렸다 내려옵니다. 방법은 "이 일은 메인에서만"이라고 그 함수에만 딱지를 붙이거나(@MainActor), 그 구간만 감싸는(MainActor.run) 거예요.

🔑 한 문장

무대를 바꾸는 것(hop)잠깐 자리를 비우는 것(suspend)은 다른 얘기다. 같은 무대라도 기다리면 자리는 비워진다.