Skip to content

Instantly share code, notes, and snippets.

@prep4gmat
Last active March 30, 2016 11:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save prep4gmat/eac0a7ce2ef006ed339d9966c14e5828 to your computer and use it in GitHub Desktop.
Save prep4gmat/eac0a7ce2ef006ed339d9966c14e5828 to your computer and use it in GitHub Desktop.
Crash when reallocating WKWebView
import UIKit
import WebKit
import XWebView
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("leak avoider deinit")
print("self = \(self.debugDescription)")
}
}
class PracticeWebView: WKWebView, UIGestureRecognizerDelegate {
func configHandlers(messageHandler: WKScriptMessageHandler?, tag: Int) {
if let handler = messageHandler {
let leakHandler = LeakAvoider(delegate: handler)
configuration.userContentController.addScriptMessageHandler(leakHandler, name: "choiceTapped")
configuration.userContentController.addScriptMessageHandler(leakHandler, name: "sizeNotification")
configuration.userContentController.addScriptMessageHandler(leakHandler, name: "pageLoaded")
configuration.userContentController.addScriptMessageHandler(leakHandler, name: "imageTapped")
// Get script that's to be injected into the document
let fastclickScript:WKUserScript = WKUserScript(source: jsStringFromFileName("fastclick"), injectionTime: WKUserScriptInjectionTime.AtDocumentEnd, forMainFrameOnly: false)
configuration.userContentController.addUserScript(fastclickScript)
let longPressScript:WKUserScript = WKUserScript(source: jsStringFromFileName("longPress"), injectionTime: WKUserScriptInjectionTime.AtDocumentEnd, forMainFrameOnly: false)
configuration.userContentController.addUserScript(longPressScript)
}
let mainJSScript:WKUserScript = WKUserScript(source: jsStringFromFileName("main"), injectionTime: WKUserScriptInjectionTime.AtDocumentEnd, forMainFrameOnly: false)
configuration.userContentController.addUserScript(mainJSScript)
let scrollJS = "function scrollTo(element, to, duration) { var start = element.scrollTop, change = to - start, currentTime = 0, increment = 20; var animateScroll = function(){ currentTime += increment; var val = Math.easeInOutQuad(currentTime, start, change, duration); element.scrollTop = val; if(currentTime < duration) { setTimeout(animateScroll, increment); } }; animateScroll(); } Math.easeInOutQuad = function (t, b, c, d) { t /= d/2; if (t < 1) return c/2*t*t + b; t--; return -c/2 * (t*(t-2) - 1) + b; };"
let scrollScript:WKUserScript = WKUserScript(source: scrollJS, injectionTime: WKUserScriptInjectionTime.AtDocumentEnd, forMainFrameOnly: false)
configuration.userContentController.addUserScript(scrollScript)
//notify
let pageLoadedJSString = "window.onload = function () {window.scrollBy(0, 0); window.webkit.messageHandlers.pageLoaded.postMessage({width: document.width, height: document.height, tag: \(tag)});};"
let pageLoadedNotificationJS:WKUserScript = WKUserScript(source: pageLoadedJSString, injectionTime: WKUserScriptInjectionTime.AtDocumentEnd, forMainFrameOnly: false)
configuration.userContentController.addUserScript(pageLoadedNotificationJS)
let sizeNotificationJSString = "MathJax.Hub.Register.StartupHook('Begin Typeset',function(){console.log('begin')}),MathJax.Hub.Register.StartupHook('End Typeset',function(){console.log('end typeset')}),MathJax.Hub.Register.StartupHook('End',function(){console.log('End');var e=document.getElementsByClassName('math-jax-content');for(console.log(e),j=0;j<e.length;j++){var t=e[j];t.className+=' math-jax-loaded'};window.scrollBy(0, 0); window.webkit.messageHandlers.sizeNotification.postMessage({width: document.width, height: document.height, tag: \(tag)});});"
let sizeNotificationJS:WKUserScript = WKUserScript(source: sizeNotificationJSString, injectionTime: WKUserScriptInjectionTime.AtDocumentEnd, forMainFrameOnly: false)
configuration.userContentController.addUserScript(sizeNotificationJS)
}
// Button Click Script to Add to Document
func jsStringFromFileName(name: String, directory: String? = nil) ->String {
let results = FileUtils.read(name, type:"js", directory: directory ?? "commonHtmlTemplates")
return results.content!
}
deinit {
print("webview deinit")
print("self = \(self.debugDescription)")
}
func scrollToTop() {
evaluateJavaScript("scrollTo(document.body, 0, 0);", completionHandler: nil)
}
override func layoutSubviews() {
scrollToTop()
let scrollSize = CGSizeMake(frame.width, frame.height)
scrollView.contentSize = scrollSize
print("scrollview width = \(scrollView.contentSize.width)")
}
}
extension WKWebView {
public func viewForZoomingInScrollView(scrollView: UIScrollView) -> UIView? {
return nil
}
}
var webView = PracticeWebView()
override func viewDidLoad() {
super.viewDidLoad()
webView.configHandlers(self, tag: 0)
webView.translatesAutoresizingMaskIntoConstraints = false
webView.navigationDelegate = self
webView.scrollView.delegate = self
view.addSubview(webView)
let VFLViews = ["webView":webView]
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("V:|[webView]|", options:NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: VFLViews))
view.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat("H:|[webView]|", options:NSLayoutFormatOptions.AlignAllCenterX, metrics: nil, views: VFLViews))
}
override func viewWillDisappear(animated: Bool) {
super.viewWillDisappear(animated)
webView.stopLoading()
webView.configuration.userContentController.removeScriptMessageHandlerForName("choiceTapped")
webView.configuration.userContentController.removeScriptMessageHandlerForName("sizeNotification")
webView.configuration.userContentController.removeScriptMessageHandlerForName("pageLoaded")
webView.configuration.userContentController.removeScriptMessageHandlerForName("imageTapped")
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment