WKWebView使用過程中的那些坑


問題產生背景:  

新開發的頁面中有一部分的界面是需要展示后端接口返回的HTML代碼,包括文字和圖片。所以就自然而然的要使用iOS原生的WebKit. 鑒於Xcode 8發布以后,編譯器支持的最低版本(Deployment Target)也變為iOS8。因此放棄了UIWebView, 直接使用WKWebView(何況蘋果宣稱WKWebView的性能相比UIWebView有了極大的提升)。

坑一:獲取不到WKWebView的高度

獲取方法:在WKWebView加載成功的代理方法里獲取WKWebView的UIScrollView的contentSize

- (void)webView:(WKWebView *)webView didFinishNavigation:(null_unspecified WKNavigation *)navigation {
    self.webViewContentHeight = self.webView.scrollView.contentSize.height;
}

運行后,發現獲取不到contentSize, 打印結果顯示(width = 0, height =0).

解決辦法:使用KVO監聽WKWebView的contentSize

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (!self.webView.isLoading) {
        if([keyPath isEqualToString:@"scrollView.contentSize"])
        {
            self.webViewContentHeight = self.webView.scrollView.contentSize.height;
            CGRect frame = self.webView.frame;
            frame.size.height = self.webViewContentHeight;
            self.webView.frame = frame;
            [self.webView sizeToFit];
        }
    }
}

Bingo! 完美取到WKWebView的height.

坑二:移除KVO的keypath時,程序crash。

- (void)dealloc {
    [self.webView removeObserver:self forKeyPath:@"scrollView.contentSize" context:nil];
}

這種情況通常出現在對同一個keypath進行兩次remove,如父類中有一個kvo, 父類在dealloc的時候remove一次,子類dealloc的時候又remove一詞。看到這里想必大家都已經知道解決思路了吧?那就是區分父類和子類的KVO,回頭看一下發現addObserver和removeObserver中都有一個context參數,沒錯,這個參數就可以用來標記我們自己添加的KVO。

[self.webView addObserver:self forKeyPath:@"scrollView.contentSize" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"DJWebKitContext"];
- (void)dealloc {
    [self.webView removeObserver:self forKeyPath:@"scrollView.contentSize" context:@"DJWebKitContext"];
}

運行一下,退出頁面的時候果然不會crash了😊

坑三: 頁面刷新時crash,代碼如下:

- (void)refreshView {
    [self constructWebView];
}

- (void)constructWebView {
    _webView = [[WKWebView alloc] initWithFrame:CGRectMake(5, 64+10, WindowWidth-10, 150)];
    self.webView.backgroundColor = [UIColor clearColor];
    self.webView.layer.borderWidth = 0.5;
    self.webView.layer.borderColor = [UIColor grayColor].CGColor;
    self.webView.scrollView.scrollEnabled = YES;
    self.webView.scrollView.directionalLockEnabled = NO;
    self.webView.scrollView.scrollsToTop = NO;
    self.webView.scrollView.userInteractionEnabled = YES;
    self.webView.navigationDelegate = self;
    [self.webView loadHTMLString:@"" baseURL:nil];
    [self.webView addObserver:self forKeyPath:@"scrollView.contentSize" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"DJWebKitContext"];
    [self.view addSubview:self.webView];
}

這個問題是由於在refreshView的時候webView屬性被重新分配了對象,那么舊的對象就會被釋放掉,但是在這個過程中並沒有將舊對象的KVO remove掉,所以就會crash。解決辦法就是在對webView分配新對象前先 remove observer,或者如果是webView不需要新對象的話,可以判斷如果webView存在,就不重新初始化:

- (void)refreshView {
    [self constructWebView];
}

- (void)constructWebView {
    if (_webView) {
        [self.webView removeObserver:self forKeyPath:@"scrollView.contentSize" context:@"DJWebKitContext"];
    }
    _webView = [[WKWebView alloc] initWithFrame:CGRectMake(5, 64+10, WindowWidth-10, 150)];
    self.webView.backgroundColor = [UIColor clearColor];
    self.webView.layer.borderWidth = 0.5;
    self.webView.layer.borderColor = [UIColor grayColor].CGColor;
    self.webView.scrollView.scrollEnabled = YES;
    self.webView.scrollView.directionalLockEnabled = NO;
    self.webView.scrollView.scrollsToTop = NO;
    self.webView.scrollView.userInteractionEnabled = YES;
    self.webView.navigationDelegate = self;
    [self.webView loadHTMLString:@"" baseURL:nil];
    [self.webView addObserver:self forKeyPath:@"scrollView.contentSize" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"DJWebKitContext"];
    [self.view addSubview:self.webView];
}

有興趣的同學可以下載demo來驗證這三個問題。同時,如果大家在使用過程中遇到過其它坑也歡迎告訴我,我會幫忙記錄下來供其他人參考。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM