생계유지형 개발자/Stack Over Flow 한국판

[ios] Completion handler passed to -[Connect.MainViewController webView:decidePolicyForNavigationAction:decisionHandler:] was called more than once

이 가을 2020. 7. 30. 17:56

# 오류

WebView 함수에서 화면 왔다갔다 하는 중에 다음과 같은 오류가 발생하면서 앱이 멈춘다.

 

Exception: "Completion handler passed to -[Connect.MainViewController webView:decidePolicyForNavigationAction:decisionHandler:] was called more than once"

 

위의 에러가 발생한 소스코드 위치는 아래에서 에러발생지점 이라고 표시한 라인이다.

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        let destinationUrl = (navigationAction.request.url?.absoluteString)! as NSString // 목적지 url  
        if destinationUrl.contains(Helper.logInUrl) {
            decisionHandler(.cancel)
        }
        if destinationUrl.hasPrefix(Helper.appSchema) {
            decisionHandler(.cancel)
        }
        decisionHandler(.allow)	// <-- 에러발생지점
    }

 

# 원인

정확한 원인은 잘 모르겠지만, 정책상(?) decisionHandler()는 한번만 호출될 수 있다.

함수가 한번 실행되는 동안 .cancel 로 했다가 .allow 로 바꿀 수 없다는 것이다.

그래서 decisionHandler()를 했으면 바로 return 시켜주는 것이 오류를  방지하는 안전한 방법이다.

# 해결

함수끝낼 때 decisionHandler 앞에 return을 붙여주거나 마지막에 Void로 return 해 주니 해결되었다. 

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
        let destinationUrl = (navigationAction.request.url?.absoluteString)! as NSString // 목적지 url  
        if destinationUrl.contains(Helper.logInUrl) {
            decisionHandler(.cancel)
            return
        }
        if destinationUrl.hasPrefix(Helper.appSchema) {
            decisionHandler(.cancel)
            return
        }
        decisionHandler(.allow)
        // return 맨 마지막 생략 가능
    }

 

※ 참고

https://github.com/marcuswestin/webviewjavascriptbridge/issues/278