本文主要解決WKWebView在通過WKUserContentController添加MessageHandler方法用于JS調(diào)用Native導致ViewController內(nèi)存泄露,無法正常釋放。
1.ViewController沒有調(diào)用dealloc可能的原因
在使用WKWebView時,ViewController在該釋放的時候沒有釋放(沒有調(diào)用- (void)dealloc方法)。參考了這篇文章檢查了ViewController中的NSTimer、delegate并將所有block中的self更換為weakSelf,結果仍然沒有調(diào)用dealloc方法。
之后檢查了ViewController中所有使用到self的地方,發(fā)現(xiàn)WKUserContentController的下面這個方法有使用到self:
App注冊方法用于JS調(diào)用
- (void)addScriptMessageHandler:(id <WKScriptMessageHandler>)scriptMessageHandler name:(NSString *)name
WKWebViewConfiguration *wkConfig = [[WKWebViewConfiguration alloc] init];
wkConfig.userContentController = [[WKUserContentController alloc] init];
[wkConfig.userContentController addScriptMessageHandler:self name:@"Native"];
所以Google了一下該方法是否會引起ViewController不調(diào)用dealloc方法。確實是由于該方法引起ViewController內(nèi)存泄漏。
搜到的結果
2. 解決方案
(1)WeakScriptMessageDelegate
可以創(chuàng)建一個新的類WeakScriptMessageDelegate,也可以將@interface-@end寫在ViewController.h中,@implementation-@end寫在ViewController.m中。
@interface WeakScriptMessageDelegate : NSObject<WKScriptMessageHandler>
@property (nonatomic, weak) id<WKScriptMessageHandler> scriptDelegate;
- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate;
@end
@implementation WeakScriptMessageDelegate
- (instancetype)initWithDelegate:(id<WKScriptMessageHandler>)scriptDelegate {
self = [super init];
if (self) {
_scriptDelegate = scriptDelegate;
}
return self;
}
- (void)userContentController:(WKUserContentController *)userContentController didReceiveScriptMessage:(WKScriptMessage *)message {
[self.scriptDelegate userContentController:userContentController didReceiveScriptMessage:message];
}
@end
(2)使用
添加了下面這行代碼之后ViewController就會調(diào)用dealloc方法,此時ViewController已經(jīng)正常釋放。但是WeakScriptMessageDelegate沒有釋放,需要在dealloc中將WeakScriptMessageDelegate釋放掉。
WKWebViewConfiguration *wkConfig = [[WKWebViewConfiguration alloc] init];
wkConfig.userContentController = [[WKUserContentController alloc] init];
[wkConfig.userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"Native"];
(3)釋放WeakScriptMessageDelegate
- (void)dealloc {
[self.wkConfig.userContentController removeScriptMessageHandlerForName:@"Native"];
}