0Pricing
Swift Academy · 강의

캡처 목록과 약한 self

[weak self]로 순환 참조를 방지합니다.

캡처 목록과 약한 self은(는) CoddyKit의 무료 Swift Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Swift Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Swift Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

참조 순환 위험

객체가 self를 강하게 캡처하는 탈출 클로저를 저장하면 서로가 상대방을 영원히 유지하게 됩니다 — 메모리 누수를 일으키는 참조 순환입니다.

강한 참조 순환

클로저는 self를 강하게 캡처하고 self는 클로저를 보유하므로 둘 다 해제되지 않습니다:

class Owner {
    var onEvent: (() -> Void)?
    func setup() {
        onEvent = { print(self.describe()) }  // strong self -> cycle
    }
    func describe() -> String { "Owner" }
}
let o = Owner(); o.setup()
o.onEvent?()  // "Owner"  (but leaks)

캡처 목록

클로저 시작 부분의 캡처 목록 { [weak self] in ... }은 캡처한 각 참조를 보관하는 방식을 제어합니다. 강한 참조 대신 weak 또는 unowned를 사용할 수 있습니다.

weak self로 순환 끊기

[weak self]는 self를 선택 사항으로 캡처하므로 self를 계속 유지하지 않습니다:

class Owner {
    var onEvent: (() -> Void)?
    func setup() {
        onEvent = { [weak self] in
            print(self?.describe() ?? "gone")
        }
    }
    func describe() -> String { "Owner" }
}
let o = Owner(); o.setup()
o.onEvent?()  // "Owner"  (no cycle)

weak를 사용하면 self가 선택 사항이 됩니다

[weak self]를 사용하면 self가 Self?가 되므로 언래핑해야 합니다:

class Worker {
    var tag = "W"
    lazy var job: () -> Void = { [weak self] in
        guard let self = self else { return }
        print(self.tag)
    }
}
let w = Worker()
w.job()  // "W"

guard let self 패턴

self를 일찍 다시 바인딩하면 클로저의 나머지 부분에서 강한 비선택적 참조를 사용할 수 있습니다:

class Service {
    var name = "S"
    lazy var run: () -> Void = { [weak self] in
        guard let self else { return }
        print(self.name)
        print("still \(self.name)")
    }
}
Service().run()  // "S" / "still S"

weak와 unowned 비교

weak는 선택적 참조를 제공하므로 객체가 이미 사라졌을 때도 안전합니다. unowned는 비선택적이고 더 빠르지만 객체가 해제된 후 접근하면 충돌합니다 — self가 클로저보다 반드시 오래 유지되는 경우에만 사용하세요.

unowned 사용하기

클로저가 self보다 오래 유지될 수 없을 때 unowned를 선택하세요:

class Timer2 {
    var ticks = 0
    lazy var tick: () -> Void = { [unowned self] in
        self.ticks += 1
    }
}
let t = Timer2()
t.tick(); t.tick()
print(t.ticks)  // 2

특정 속성 캡처하기

self 전체 대신 필요한 항목만 캡처하세요 — 때로는 이렇게 하면 순환을 완전히 피할 수 있습니다:

class VM {
    let id = 42
    lazy var printer: () -> Void = { [id] in print(id) }
}
VM().printer()  // 42

비탈출 클로저에는 weak가 필요하지 않습니다

map처럼 동기적으로 실행되는 비탈출 클로저는 순환을 만들지 않으므로, 그 안에서 self를 강하게 캡처해도 괜찮습니다:

class Calc {
    let factor = 3
    func scale(_ xs: [Int]) -> [Int] {
        xs.map { $0 * self.factor }   // safe, non-escaping
    }
}
print(Calc().scale([1, 2]))  // [3, 6]

기억해 둘 원칙

self를 참조하는 저장된 탈출 클로저에는 [weak self]를 사용하세요. self가 살아 있다고 보장되는 경우에만 unowned를 선택하세요. 비탈출 클로저에는 캡처 목록을 생략하세요.

class P {
    var n = "P"
    var stored: (() -> Void)?
    func arm() { stored = { [weak self] in print(self?.n ?? "-") } }
}
let p = P(); p.arm(); p.stored?()  // "P"

빠른 확인

저장된 탈출 클로저에서 [weak self]를 사용하는 이유는 무엇인가요?

복습

캡처 목록에 대해 배웠습니다:

  • 저장된 탈출 클로저에서 self를 강하게 캡처하면 참조 순환이 생깁니다(메모리 누수)
  • [weak self]가 순환을 끊고 self가 선택 사항이 되므로 guard let self을 사용합니다
  • unowned는 비선택적이고 더 빠르지만 self가 사라진 후 접근하면 충돌합니다
  • 비탈출 클로저에는 캡처 목록이 필요하지 않습니다

다음: 오토클로저

자주 묻는 질문

“캡처 목록과 약한 self” 강의는 무료인가요?

네 — “캡처 목록과 약한 self” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Swift Academy 강의 전체를 잠금 해제할 수 있습니다. Swift Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“캡처 목록과 약한 self”에서 뭘 배우나요?

[weak self]로 순환 참조를 방지합니다. 브라우저에서 직접 실행하는 실습 코드로 Swift Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Swift Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Swift Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“캡처 목록과 약한 self” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Swift Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Swift Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 참조로 값 캡처하기
  2. 이스케이핑 클로저
  3. 캡처 목록과 약한 self
  4. 자동 클로저
← Swift Academy(으)로 돌아가기