Memory leaks in the interaction between WKWebView and js

Recently, I suddenly found that the memory of the rich text post details has not been released. After searching for a long time, I couldn't find the problem. I finally found the problem today. Let's put a code snippet first.

WKWebViewConfiguration *configuration = [[WKWebViewConfiguration alloc] init];
configuration.userContentController = [WKUserContentController new];

    [configuration.userContentController addScriptMessageHandler:self name:@"jumpWeiboPostimage"];
    
    WKPreferences *preferences = [WKPreferences new];
    preferences.javaScriptCanOpenWindowsAutomatically = NO;
    preferences.javaScriptEnabled = YES;
    configuration.preferences = preferences;
    
    WKWebView *webView = [[WKWebView alloc] initWithFrame:CGRectMake(WebViewX, 0, self.view.width - WebViewX * 2, 1) configuration:configuration];
    webView.scrollView.bounces = NO;
    webView.scrollView.scrollEnabled = NO;
    webView.UIDelegate = self;
    webView.navigationDelegate = self;
    [self.headerView addSubview:webView];

The system methods called by all the above snippets seem to be harmless, but they actually hide murderous intentions. No one would have thought that this place has been here for me for many days.

The problem comes from the addScriptMessageHandler: name: method, one of which is passed in here is self, which is an instance of this class. The following is from my own guess: configuration has this class instance and this class has webView, and webView has configuration, which leads to circular references, of course The main premise is that the configuration is a strong reference to this class. If it is a weak reference, there should be no circular reference problem.

So the first method can call removeScriptMessagehandlerForname: to manually cancel the added method when the page is launched again to achieve the effect of releasing vc.

Since the instance of this class is passed in when calling addScriptMessageHandler: name: and it cannot be released, you can define a separate class and pass in this class to transition

@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

At this point, when the webView registration configuration is initialized, it will be modified to

[configuration.userContentController addScriptMessageHandler:[[WeakScriptMessageDelegate alloc] initWithDelegate:self] name:@"jumpWeiboPostimage"];

This is you will find that the dealloc method of vc will be called, but there is a problem that the transition class just now has not been released. At this time, in the dealloc method, the method of registering and monitoring the webView can be removed.

[self.configuration.userContentController removeScriptMessageHandlerForName:@"jumpWeiboPostimage"];

 

by: Hatsumitsu

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324860071&siteId=291194637