[swift] 클로저 사용시 주의할 점

클로저는 Swift에서 매우 강력한 기능 중 하나로, 코드 블럭을 일급 객체로 사용할 수 있게 해줍니다. 하지만 클로저를 사용할 때 몇 가지 주의해야 할 사항이 있습니다. 이번 포스트에서는 클로저를 사용할 때 주의해야 할 점에 대해 알아보겠습니다.

1. 클로저 캡처 주기

클로저는 주변의 변수와 상수를 캡처하여 사용할 수 있습니다. 하지만 클로저가 캡처한 변수와 상수는 클로저의 생명 주기와 관련이 있습니다. 클로저를 정의한 스코프가 종료되더라도 클로저가 변수나 상수에 대한 참조를 유지하는 경우, 메모리 누수가 발생할 수 있습니다. 이러한 경우, 클로저를 약한 참조([weak self])로 선언하여 강한 참조 순환을 피해야 합니다.

예시:

class ExampleClass {
    var closure: (() -> Void)?
    
    func setupClosure() {
        closure = { [weak self] in
            // 클로저 내부에서 self 사용
        }
    }
    
    deinit {
        print("ExampleClass deallocated")
    }
}

2. 클로저 사용시 메모리 관리

클로저 내에서 강한 참조 순환 문제가 발생하지 않더라도, 사용되지 않는 메모리를 계속 유지할 수 있습니다. 클로저 내에서 사용한 리소스를 적절하게 해제하지 않으면, 메모리 누수가 발생합니다. 따라서 클로저를 사용하는 경우, 메모리 관리에 주의해야 합니다.

예시:

class ExampleClass {
    var closure: (() -> Void)?
    
    func setupClosure() {
        closure = {
            // 리소스를 사용하는 작업
        }
    }
    
    func cleanupClosure() {
        closure = nil // 클로저 참조 해제
    }
    
    deinit {
        print("ExampleClass deallocated")
    }
}

3. 클로저 순환 참조

클로저 내에서 객체를 강한 참조하는 경우, 객체와 클로저 간의 순환 참조 문제가 발생할 수 있습니다. 이 경우, 클로저를 약한 참조([weak self])로 선언하거나, 클로저 내에서 캡처한 객체를 명시적으로 해제해야 합니다.

예시:

class ExampleClass {
    var closure: (() -> Void)?
    
    func setupClosure() {
        closure = { [weak self] in
            guard let self = self else { return }
            
            // 객체 사용
        }
    }
    
    deinit {
        print("ExampleClass deallocated")
    }
}

클로저는 매우 강력한 기능이지만, 이를 제대로 관리하지 않으면 예상치 못한 문제들이 발생할 수 있습니다. 위의 주의사항을 참고하여 클로저를 사용할 때 에러와 메모리 관리를 적절하게 다루는 것이 중요합니다.


참고 문서: