2016-02-20 17 views
8

Mam tę hierarchię - UIViewController -> ChildUIViewController -> WKWebView.WKWebView ulega awarii na deinit

Wystąpił problem z obsługą komunikatów WKWebView, która wyciekła i uniemożliwiono zwolnienie kontrolera podrzędnego.

Po pewnym czytania Znalazłem sposób ustalić cykl zatrzymania przy użyciu tej poprawki - WKWebView causes my view controller to leak

Teraz widzę, że kontroler widoku dziecko osiąga deinit ale tuż po tym WKWebView jest upaść na deinit (Nie przydatny log z Xcode).

Każda idea lub kierunek, jaki może być problem?

Dzięki

UPDATE tutaj jest mój kod - Code Gist

Odpowiedz

8

Umieść ten wewnątrz metody deinit widzenia dziecięcej kontrolera:

webView.scrollView.delegate = nil 
+0

Wow. Dzięki! Uderzyliśmy głową w to, czy możesz wyjaśnić, jak się dowiedziałeś? – shannoga

+0

@shannoga wygląda jak 'WKWebView' przechowuje' __unsafe_unretained' wskaźnik do twojego delegata. Czasami w widoku sieci zwalnianym nie następuje natychmiastowe zwolnienie kontrolera, co powoduje awarię, gdy widok WWW próbuje powiadomić delegata o czymś. –

1

Próbowałem z sam sposób jak wspomniano. Działa to idealnie dla mnie. Kod który próbowałem znaczy

class CustomWKWebView : WKWebView { 

    deinit { 
     print("CustomWKWebView - dealloc") 
    } 

} 


class LeakAvoider : NSObject, WKScriptMessageHandler { 
    weak var delegate : WKScriptMessageHandler? 
    init(delegate:WKScriptMessageHandler) { 
     self.delegate = delegate 
     super.init() 
    } 
    func userContentController(userContentController: WKUserContentController, 
     didReceiveScriptMessage message: WKScriptMessage) { 
      self.delegate?.userContentController(
       userContentController, didReceiveScriptMessage: message) 
    } 

    deinit { 
     print("LeakAvoider - dealloc") 
    } 

} 

class ChildViewController: UIViewController , WKScriptMessageHandler{ 

    var webView = CustomWKWebView() 

    override func viewDidLayoutSubviews() { 
     super.viewDidLayoutSubviews() 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     view.addSubview(webView) 
     webView.frame = self.view.bounds; 
    } 

    override func viewDidAppear(animated: Bool) { 
     super.viewDidAppear(animated) 
     let url = NSURL(string: "https://appleid.apple.com") 
     webView.loadRequest(NSURLRequest(URL:url!)) 
     webView.configuration.userContentController.addScriptMessageHandler(
      LeakAvoider(delegate: self), name: "dummy") 
    } 

    func userContentController(userContentController: WKUserContentController, didReceiveScriptMessage message: WKScriptMessage) 
    { 

    } 

    deinit { 
     print("ChaildViewController- dealloc") 
     webView.stopLoading() 
     webView.configuration.userContentController.removeScriptMessageHandlerForName("dummy") 
    } 
} 


class ViewController: UIViewController { 

    override func viewDidLayoutSubviews() { 
     super.viewDidLayoutSubviews() 
    } 

    override func viewDidLoad() { 
     super.viewDidLoad() 
    } 

    deinit { 
     print("ViewController - dealloc") 
    } 
} 

Log po popping ViewController jest:

ViewController - dealloc 
ChaildViewController- dealloc 
LeakAvoider - dealloc 
CustomWKWebView - dealloc 

UPDATE

umieścić poniżej linii w funkcji Twojego WebViewViewController za viewWillDisappear.

webView.navigationDelegate = nil 
    webView.scrollView.delegate = nil 

Próbowałem, ustawiając tych dwóch delegatów w moim kodzie i zaczął się zawiesza. Rozwiązano, umieszczając powyższe linie w widokuOdkrywanie obiektu ChildViewController.

+0

Dzięki za wykonaną pracę. Sprawdzę z innych powodów. – shannoga

0

Pamiętaj, przyczyną może być słabe odniesienie do niego. Jestem pewien, że stworzyłeś lokalną zmienną klasy zawijanej za pomocą WKWebView.

+0

Dzięki. Czy możesz wyjaśnić lepiej? Problem wygląda teraz tak, jakby WebView został ponownie przydzielony dwukrotnie – shannoga

+0

, ponieważ próbuje, zwolnić zmienną nieistniejącą. Umieść swój kod na goglach, to może ci pomóc. – dimpiax

+0

Dodaję sens z moim kodem, niedługo zabijemy siebie :(, dziękuję za pomoc- https://gist.github.com/prep4gmat/eac0a7ce2ef006ed339d9966c14e5828 – shannoga

3

Nie zapomnij usunąć delegatów WKWebView za dodano:

deinit { 
    webView.navigationDelegate = nil 
    webView.scrollView.delegate = nil 
} 

Wygląda sklepy WKWebView __unsafe_unretained wskaźnik do swojego delegata . Czasami, gdy widok sieci został zwrócony nie natychmiast po obejrzeniu kontrolera. Powoduje to awarię, gdy widok WWW próbuje powiadomić delegata o czymś.