반응형
Notice
Recent Posts
Recent Comments
Link
- Today
- Total
07-18 06:00
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 | 31 |
Tags
- sigmoid
- Python
- Observable
- 연산자
- 시각화
- struct
- HTTP
- SQL
- scheduledTimer
- rest api
- MVC
- 딥러닝
- swiftUI
- 티스토리챌린지
- Request
- Optional
- SWIFT
- decode
- substr
- ios
- ReLU
- 명령어
- barplot
- deeplearning
- cocoapods
- 오블완
- rxswift
- r
- Linux
- tapply
Archives
iOS 개발 기록 블로그
[iOS] WKWebView에서 발생하는 retain cycle과 메모리 릭 해결하기 본문
반응형
WKWebView, 왜 갑자기 메모리 릭이 생기지?
WKWebView를 개발하면서 통칭 '브릿지'라고 하는 기능을 담당하는 WKScriptMessageHandler를 사용하여 브릿지를 네이티브에서 추가해주게 됩니다.
WKWebView를 사용할 때 WKScriptMessageHandler를 사용해 JavaScript 브릿지를 연결하다 보면, 어느 순간 deinit이 호출되지 않고 VC가 메모리에 남아 있는 걸 발견하게 됩니다.
contentController.add(self, name: "myBridge")
위처럼 추가해주고 저 같은 경우에 기존 방식으로 deinit 시점에 아래와 같이 수동으로 제거해주곤 합니다.
webView.configuration.userContentController.removeAllScriptMessageHandlers()
문제 원인: WebView가 VC를 retain하고 있다!
WebKit은 add(_:name:)로 넘겨준 객체(self, 즉 VC)를 강하게 참조합니다.
그리고 VC는 WebView를 서브뷰로 갖고 있죠.
즉, 이런 구조가 만들어집니다.
VC (나 자신) ───▶ WebView ───▶ 나 자신
▲ │
└────── retain cycle ─────┘
순환 참조(Retain Cycle) 발생.
그래서 deinit이 호출되지 않고, removeScriptMessageHandler()를 해줘도 늦는 경우가 많습니다.
해결 방법: Weak Proxy 패턴 도입하기
VC를 직접 넘기지 말고, 중간에 weak 참조만 가지는 래퍼를 끼워줍니다.
VC (진짜 나) ◀─── WeakScriptMessageHandler ◀─── WebView
▲ │
└──── weak reference ────┘
WeakScriptMessageHandler 클래스
final class WeakScriptMessageHandler: NSObject, WKScriptMessageHandler {
weak var delegate: WKScriptMessageHandler?
init(_ delegate: WKScriptMessageHandler) {
self.delegate = delegate
}
func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
delegate?.userContentController(userContentController, didReceive: message)
}
}
사용
let contentController = WKUserContentController()
contentController.add(WeakScriptMessageHandler(self), name: "myBridge")
이 방법은 WebKit이 handler를 강하게 유지하더라도, 실질적으로 retain 되는 객체는 WeakScriptMessageHandler이므로 VC는 해제됩니다.
결과
- ✅ VC가 더 이상 WebView에 의해 retain되지 않음
- ✅ deinit이 정상적으로 호출됨
- ✅ removeScriptMessageHandler()를 따로 호출할 필요 없음
- ✅ 사이드 이펙트 없이 안정적
요약
VC retain 여부 | WebView가 VC를 강하게 retain | Weak proxy가 VC를 약하게 참조 |
retain cycle | 발생 | 발생하지 않음 |
removeScriptMessageHandler | 필요함 | 불필요 |
안정성 | 낮음 | 높음 |
이 패턴은 WebView 뿐 아니라 delegate 패턴에서 순환 참조를 피할 때도 널리 사용됩니다.
WKWebView를 자주 사용하는 앱이라면 이 방식을 공통 컴포넌트로 만들어두는 것도 좋습니다.
반응형
'iOS' 카테고리의 다른 글
이미 PR에 포함된 파일을 .gitignore에 추가 후 PR에서 제외하는 방법 (1) | 2025.06.27 |
---|---|
Xcode 빌드 에러: 'Could not locate device support files' (Using Xcodes) (0) | 2025.01.14 |
Xcode 16 + iOS 18 UICollectionView 크래시 원인 및 개선 방안: NSInternalInconsistencyException (0) | 2025.01.12 |
[Swift] 프로퍼티를 init 메서드에서 초기화, 선언 시 초기화 차이 (1) | 2024.09.11 |
Swift ReactorKit @Pulse 사용 목적, 예시, 일반 State와의 차이 (0) | 2024.06.01 |