本文主要解決WKWebView在通過WKUserContentController添加MessageHandler方法用于JS調(diào)用Native導(dǎo)致ViewController內(nèi)存泄露,無法正常釋放。
1.ViewController沒有調(diào)用dealloc可能的原因
在使用WKWebView時(shí)瑞躺,ViewController在該釋放的時(shí)候沒有釋放(沒有調(diào)用- (void)dealloc
方法)。參考了這篇文章檢查了ViewController中的NSTimer循捺、delegate并將所有block中的self更換為weakSelf,結(jié)果仍然沒有調(diào)用dealloc方法雄人。
之后檢查了ViewController中所有使用到self的地方从橘,發(fā)現(xiàn)WKUserContentController的下面這個(gè)方法有使用到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了一下該方法是否會(huì)引起ViewController不調(diào)用dealloc方法。確實(shí)是由于該方法引起ViewController內(nèi)存泄漏。
搜到的結(jié)果
2. 解決方案
(1)WeakScriptMessageDelegate
可以創(chuàng)建一個(gè)新的類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就會(huì)調(diào)用dealloc方法牺勾,此時(shí)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"];
}