<aside> 🔑 순환 참조(Retain cycle)로 인한 메모리누수(memory leak)을 방지하기 위하여 사용합니다. 약한 참조라는 것은 참조하는 인스턴스를 강하게 유지하지 않는, 즉 약하게 참조한다는 것으로, ARC 가 참조된 인스턴스를 처리하지 않는것을 막지 않는다는 걸 말한다. ARC가 참조하는 인스턴스가 할당 해제되면 nil로 약한 참조를 자동으로 설정한다.

</aside>

해당 메소드가 종료된 이후에도 메모리에 남아 있을 수도 있다는 것을 의미합니다. 그리고 두 가지 상황을 만족할 때 [weak self] 를 사용하지 않는다면 Retain Cycle(순환 참조) 이 생길 수 있습니다.

**weak self**는 Swift 프로그래밍 언어에서 사용되는 메모리 관리 기법 중 하나로, retain cycle이 발생할 수 있는 클로저(Closure)나 콜백(Callback) 함수 내에서 self 참조를 약한 참조(Weak Reference)로 캡처하는 것을 의미합니다.

**weak self**를 사용하여 클로저나 콜백 함수가 **self**를 강한 참조(Strong Reference)로 캡처하는 것을 방지함으로써, retain cycle을 피할 수 있습니다. retain cycle은 메모리 누수(Memory Leak)의 주요 원인 중 하나로, 참조 간에 순환 참조가 형성되어 메모리가 정리되지 않고 계속 남아있는 상황을 말합니다.

**weak self**를 사용하는 방법은 아래와 같습니다:

class MyClass {
    var completionBlock: (() -> Void)?

    func doSomething() {
        // [weak self]를 사용하여 self를 약한 참조로 캡처
        DispatchQueue.global().async { [weak self] in
            // self를 사용하는 클로저 내부에서는 self가 nil인지 확인 후 사용
            guard let self = self else { return }
            
            // self 사용
            self.completionBlock?()
        }
    }
}

위 예시에서 DispatchQueue.global().async 메소드로 실행되는 클로저 내에서 **self**를 약한 참조로 캡처하였습니다. 그리고 클로저 내부에서 **self**를 사용하기 전에 nil인지 확인하고, 안전하게 사용하고 있습니다.

이를 통해, 클로저나 콜백 함수 내에서 **self**를 강한 참조로 캡처하여 retain cycle이 발생하는 것을 방지할 수 있고, 메모리 누수를 예방할 수 있습니다.

[weak self란?]

[Swift 문법] weak self는 왜 쓸까?

[weak self] 무조건 사용하는게 맞는걸까? 🤔

@escaping closure가 아니라면 컴파일러는 method가 종료되고 나서 해당 클로저가 사용되지 않는 것을 확인합니다. 아래 map 이 종료된 후, 다시 map을 호출한 곳으로 돌아오면 인자로 전달한 클로저는 더이상 메모리에 올라가지 않을것이라는것을 의미합니다. 따라서 @escaping closure를 다루지 않을 때는 [weak self] 를 이용해 약한 참조를 쓸 필요가 없습니다. 왜냐하면 non escaping closure에서는 Retain Cycle(순환 참조)를 만들 수 없기 때문입니다.

class ViewModel {

    func format(_ value: Int) -> String { /* some logic here... */ }

    var handler: ((Int) -> Void)? = nil

    func code() {
        // 1st example
        let formatted = [1, 2, 3].map { [weak self] value in
            return self?.format(value)
        }
        print(formatted)
    }
}
///
/// Submits a work item to a dispatch queue for asynchronous execution after
/// a specified time.
///
/// - parameter: deadline the time after which the work item should be executed,
/// given as a `DispatchTime`.
/// - parameter qos: the QoS at which the work item should be executed.
///	Defaults to `DispatchQoS.unspecified`.
/// - parameter flags: flags that control the execution environment of the
/// work item.
/// - parameter execute: The work item to be invoked on the queue.
/// - SeeAlso: `async(execute:)`
/// - SeeAlso: `asyncAfter(deadline:execute:)`
/// - SeeAlso: `DispatchQoS`
/// - SeeAlso: `DispatchWorkItemFlags`
/// - SeeAlso: `DispatchTime`
///
public func asyncAfter(deadline: DispatchTime, qos: DispatchQoS = .unspecified, flags: DispatchWorkItemFlags = [], execute work: @escaping @convention(block) () -> Void)

클로저가 인자로써 @escaping closure(execute work: @escaping @convention(block) () -> Void)) 로 전달됩니다. 이런 경우 주의가 필요합니다.

Escaping 클로저는 클로저가 해당 메소드가 종료된 이후에도 메모리에 남아 있을 수도 있다는 것을 의미합니다. 그리고 두 가지 상황을 만족할 때 [weak self] 를 사용하지 않는다면 Retain Cycle(순환 참조) 이 생길 수 있습니다.