fix: Add memory leak prevention and proper WebView cleanup

- Add dismantleUIView method to properly cleanup WebView resources
- Remove script message handlers to prevent memory leaks
- Add cleanup() method to WebViewCoordinator with timer invalidation
- Clear all callbacks and references when view is destroyed
- Add isCleanedUp guard to prevent double cleanup
- Improve memory management for better stability
This commit is contained in:
Ilyas Hallak 2025-09-30 23:20:00 +02:00
parent 4c180c6a81
commit f50ad505ae

View File

@ -284,6 +284,29 @@ struct WebView: UIViewRepresentable {
webView.loadHTMLString(styledHTML, baseURL: nil) webView.loadHTMLString(styledHTML, baseURL: nil)
} }
// CRITICAL: Proper cleanup when view is destroyed
func dismantleUIView(_ webView: WKWebView, coordinator: WebViewCoordinator) {
print("🔴 WebView - DISMANTLING: Starting cleanup")
// Stop all loading
webView.stopLoading()
// Remove navigation delegate
webView.navigationDelegate = nil
// Remove message handlers to prevent memory leaks
webView.configuration.userContentController.removeScriptMessageHandler(forName: "heightUpdate")
webView.configuration.userContentController.removeScriptMessageHandler(forName: "scrollProgress")
// Clear content
webView.loadHTMLString("", baseURL: nil)
// Cleanup coordinator
coordinator.cleanup()
print("🔴 WebView - DISMANTLING: Cleanup completed")
}
func makeCoordinator() -> WebViewCoordinator { func makeCoordinator() -> WebViewCoordinator {
WebViewCoordinator() WebViewCoordinator()
} }
@ -321,6 +344,12 @@ class WebViewCoordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler
var pendingHeight: CGFloat = 0 var pendingHeight: CGFloat = 0
var scrollVelocity: Double = 0 var scrollVelocity: Double = 0
var lastScrollTime: Date = Date() var lastScrollTime: Date = Date()
private var isCleanedUp = false
deinit {
print("🔴 WebViewCoordinator - deinit called")
cleanup()
}
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
if navigationAction.navigationType == .linkActivated { if navigationAction.navigationType == .linkActivated {
@ -407,4 +436,23 @@ class WebViewCoordinator: NSObject, WKNavigationDelegate, WKScriptMessageHandler
lastHeight = height lastHeight = height
onHeightChange?(height) onHeightChange?(height)
} }
func cleanup() {
guard !isCleanedUp else { return }
isCleanedUp = true
print("🔴 WebViewCoordinator - cleanup: Invalidating timers")
// Invalidate all timers
scrollEndTimer?.invalidate()
scrollEndTimer = nil
heightUpdateTimer?.invalidate()
heightUpdateTimer = nil
// Clear callbacks to prevent memory leaks
onHeightChange = nil
onScroll = nil
print("🔴 WebViewCoordinator - cleanup: Completed")
}
} }