Swift에서 클로저(closures)는 주변 문맥의 변수와 상수에 대한 참조를 캡처하고 저장할 수 있는 독립적인 코드 블록입니다. 클로저는 콜백(callback), 비동기 처리 및 코드 실행을 변수 값으로 저장할 수 있게 해줍니다.
var counter = 0 let incrementer: () -> Void = { counter += 1 } incrementer() print(counter) // 1
[weak self], [unowned self]).self를 캡처할 때 발생할 수 있는 retain cycle입니다.strong-capture와
[weak self]또는[unowned self]를 캡처 목록에서 사용하는 것의 차이는 무엇입니까? 어떤 결과를 초래할 수 있습니까?
답변:
[weak self] 또는 [unowned self]를 지정하지 않으면 클로저는 기본적으로 self를 강한 참조로 캡처하게 되어, 클로저와 self가 서로를 참조하게 되면 retain cycle이 발생할 수 있습니다. [weak self]는 self를 약한 참조(옵셔널)로 캡처하고, [unowned self]는 비컨트롤 가능한 참조(비옵셔널)로 캡처합니다. 캡처 목록의 잘못된 선택이나 부재는 메모리 누수 또는 크래시를 초래할 수 있습니다.
class Test { var closure: (() -> Void)? func setup() { closure = { [weak self] in self?.doWork() } } func doWork() { ... } }
이야기
프로그래머가 UIViewController 내의 클로저에서 캡처 목록을 사용하지 않아 비동기 데이터 로드를 시작했습니다. 결과적으로 controller와 그의 view가 해제되지 않아 dismiss 후 메모리 누수가 발생했습니다. 인프라 분석 결과 수백 개의 "고립된" 메모리에서 컨트롤러가 발견되었습니다.
이야기
클로저가 [unowned self]를 사용하여 self를 캡처했지만, self의 생명 주기가 클로저 이전에 종료되었습니다. 이미 해제된 객체에 접근하려 할 때 크래시가 발생하여 클로저 내에서 self로 작업할 때 애플리케이션이 종료되었습니다.
이야기
프로젝트 내에서 중첩된 클로저가 두 변수를 캡처했는데, 하나는 강한 참조로, 다른 하나는 약한 참조로 캡처되었다. 약한 참조가 너무 일찍 nullified 되어 클로저 작업에 필요한 데이터가 손실되었습니다 — 이 버그는 다중 스레드 환경에서 스트레스 테스트 중에만 발생했습니다.