不确定我是否遇到了WebKit中的错误或者我正在做一些可怕的错误,但我无法弄清楚如何使用WKScriptMessageHandler而不会导致WKScriptMessage.body中包含的任何值泄漏.
我能够组建一个最小的Mac项目来隔离问题,但无济于事.
在主视图控制器中:
class ViewController: NSViewController { var webView: WKWebView? override func viewDidLoad() { super.viewDidLoad() let userContentController = WKUserContentController() userContentController.addScriptMessageHandler(self,name: "handler") let configuration = WKWebViewConfiguration() configuration.userContentController = userContentController webView = WKWebView(frame: CGRectZero,configuration: configuration) view.addSubview(webView!) let path = NSBundle.mainBundle().pathForResource("index",ofType: "html") let url = NSURL(fileURLWithPath: path!)! webView?.loadRequest(NSURLRequest(URL: url)) } } extension ViewController: WKScriptMessageHandler { func userContentController(userContentController: WKUserContentController,didReceiveScriptMessage message: WKScriptMessage) { print(message.body) } }
然后在index.html文件中:
<html> <head></head> <body> <script type="text/javascript"> webkit.messageHandlers.handler.postMessage("Here's a random number for you: " + Math.random() * 10) </script> </body> </html>
当我运行项目然后在Instruments中打开内存调试器时,我看到以下泄漏:
如果我添加一个重新加载请求的按钮,并且这样做了几十次,那么应用程序的内存占用量会不断增长,并在达到某个阈值后崩溃.在这个最小的例子中崩溃可能需要一段时间,但在我的应用程序中,我每秒收到几条消息,崩溃所需的时间不到10秒.
整个项目可以是downloaded here.
知道发生了什么事吗?
解决方法
您所看到的是WebKit错误:
https://bugs.webkit.org/show_bug.cgi?id=136140.它是
fixed in WebKit trunk a while ago,但似乎没有合并到任何WebKit更新中.
您可以通过向WKScriptMessage添加-dealloc来解决此问题,以补偿过度保留.它可能看起来像这样:
// // WKScriptMessage+WKScriptMessageLeakFix.m // TestWebkitMessages // // Created by Mark Rowe on 6/27/15. // Copyright © Mark Rowe. // // Permission is hereby granted,free of charge,to any person obtaining a copy of this software and // associated documentation files (the "Software"),to deal in the Software without restriction,// including without limitation the rights to use,copy,modify,merge,publish,distribute,sublicense,// and/or sell copies of the Software,and to permit persons to whom the Software is furnished to do so,// subject to the following conditions: // // The above copyright notice and this permission notice shall be included in all copies or substantial // portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS",WITHOUT WARRANTY OF ANY KIND,EXPRESS OR IMPLIED,INCLUDING BUT NOT // LIMITED TO THE WARRANTIES OF MERCHANTABILITY,FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. // IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,DAMAGES OR OTHER LIABILITY,// WHETHER IN AN ACTION OF CONTRACT,TORT OR OTHERWISE,ARISING FROM,OUT OF OR IN CONNECTION WITH THE // SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #import <mach-o/dyld.h> #import <objc/runtime.h> #import <WebKit/WebKit.h> // Work around <https://webkit.org/b/136140> WKScriptMessage leaks its body @interface WKScriptMessage (WKScriptMessageLeakFix) @end @implementation WKScriptMessage (WKScriptMessageLeakFix) + (void)load { // <https://webkit.org/b/136140> was fixed in WebKit trunk prior to the first v601 build being released. // Enable the workaround in WebKit versions < 601. In the unlikely event that the fix is backported,this // version check will need to be updated. int32_t version = NSVersionOfRunTimeLibrary("WebKit"); int32_t majorVersion = version >> 16; if (majorVersion > 600) return; // Add our -dealloc to WKScriptMessage. If -[WKScriptMessage dealloc] already existed // we'd need to swap implementations instead. Method fixedDealloc = class_getInstanceMethod(self,@selector(fixedDealloc)); IMP fixedDeallocIMP = method_getImplementation(fixedDealloc); class_addMethod(self,@selector(dealloc),fixedDeallocIMP,method_getTypeEncoding(fixedDealloc)); } - (void)fixedDealloc { // Compensate for the over-retain in -[WKScriptMessage _initWithBody:webView:frameInfo:name:]. [self.body release]; // Call our WKScriptMessage's superclass -dealloc implementation. [super dealloc]; } @end
将它放在项目的Objective-C文件中,将此文件的编译器标志设置为包含-fno-objc-arc,它应该为您处理泄漏.