最近一直在做手机H5的东西,网页写多了,测试也测出问题来了,打开十几个网页后,app出现无响应,app的webview界面出现黑屏等等奇怪的问题。

我试了几遍,APP内存占用从20M飙升到100M+,到了100M的时候,xcode被断开了,然后问题就一个个冒出来了-_-!

搜索了一下,是uiwebview内存泄漏,然后我就兼容了wkwebview。

wkwebview遇到的问题主要有几个:

1、多个wkwebview数据不同步,localstorage在a页面能用,去到b页面能用,在b页面写入东西,在a页面看不到

2、跳转新增webview,加载很慢

3、receiveMemoryWarning 之后,或者一段时间没用之后,返回之前的页面,页面变成空白

我解决了这几个问题,并写了一个替代的兼容webview


所以标题也可以叫uiwebview的无痛迁移


//
//  GsWebView.swift
//  iosclient
//
//  Created by Yeshen on 16/8/31.
//  copyright © 2016年 L. All rights reserved.
//

import Foundation
import UIKit
import WebKit

protocol GsWebViewDelegate{
    func webView(webView: GsWebView,shouldStartLoadWithRequest request: String?) -> Bool
    func webViewDidStartLoad(webView: GsWebView)
    func webViewDidFinishLoad(webView: GsWebView)
    func webView(webView: GsWebView,didFailLoadWithError error: NSError?)
}

class GsWebView :NSObject,UIWebViewDelegate,WKNavigationDelegate,WKUIDelegate{
    var delegate:GsWebViewDelegate?
    var view:UIView?
    
    init(frame:CGRect) {
        super.init()
        if #available(iOS 8.0,*) {
            let config = WKWebViewConfiguration()
            config.processpool = Processpool.ins.get()
            config.preferences = Processpool.ins.getPreferences()
            let v = WKWebView(frame: frame,configuration: config)
            v.navigationDelegate = self
            v.UIDelegate = self
            v.opaque = false

            self.view = v
        }else{
            let v = UIWebView(frame: frame)
            v.delegate = self
            v.dataDetectorTypes = UIDataDetectorTypes.None
            self.view = v
        }
    }
    
    func loadRequest(url:String){
        if let url = NSURL(string: url.EncodeURL()){
            let request = NSURLRequest(URL: url)
            if #available(iOS 8.0,*) {
                if let wkweb = view as? WKWebView {
                    wkweb.loadRequest(request)
                }
            } else {
                if let uiweb = view as? UIWebView{
                    uiweb.loadRequest(request)
                }
            }
        }
    }
    func setBackgroundColor(color:UIColor){
        view?.backgroundColor = color
    }
    
    func getScrollView() -> UIScrollView?{
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                return wkweb.scrollView
            }
        } else {
            if let uiweb = view as? UIWebView{
                return uiweb.scrollView
            }
        }
        return nil
    }
    
    func runjs(action:String?){
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                wkweb.runjs(action)
            }
        } else {
            if let uiweb = view as? UIWebView{
                uiweb.runjs(action)
            }
        }
    }
    
    func JavaScriptGet(action:String?,callback:((AnyObject?,NSError?) -> Void)){
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                wkweb.JavaScriptGet(action,callback: callback)
                return
            }
        } else {
            if let uiweb = view as? UIWebView{
                let str = uiweb.JavaScriptGet(action)
                callback(str,nil)
                return
            }
        }
        callback(nil,nil)
    }
    
    func getTitle() -> String{
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                return wkweb.getTitle()
            }
        } else {
            if let uiweb = view as? UIWebView{
                return uiweb.getTitle()
            }
        }
        return Strings.empty
    }
    
    func reloadFromOrigin(){
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                wkweb.reloadFromOrigin()
            }
        } else {
            if let uiweb = view as? UIWebView{
                uiweb.reload()
            }
        }
    }
    
    func reload(){
        self.reload(nil)
    }
    
    func reload(optionalUrl:String?){
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                if(wkweb.URL == nil && optionalUrl != nil){
                    loadRequest(optionalUrl!)
                    return
                }
                wkweb.reload()
            }
        } else {
            if let uiweb = view as? UIWebView{
                uiweb.reload()
            }
        }
    }
    
    func canGoBack() -> Bool{
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                return wkweb.canGoBack
            }
        } else {
            if let uiweb = view as? UIWebView{
                return uiweb.canGoBack
            }
        }
        return false
    }
    
    func goBack() {
        if #available(iOS 8.0,*) {
            if let wkweb = view as? WKWebView {
                wkweb.goBack()
            }
        } else {
            if let uiweb = view as? UIWebView{
                uiweb.goBack()
            }
        }
    }
    
    //call on viewDidAppear
    //for wkwebview'bug : Blank screen after running app for a while
    var ensure:Int = 0
    func ensurePageValid(){
        if #available(iOS 8.0,*) {
            ensure++
            if(ensure > 1){
                JavaScriptGet("document.body.children.length > 0",callback: {(data,error) -> Void in
                    var isVaild = true
                    if(error == nil && data != nil){
                        if let vaild = data as? Bool{
                            isVaild = vaild
                        }
                    }else if(error != nil){
                        if(error?.domain == WKErrorDomain && error?.code == 1){
                            isVaild = false
                        }
                    }
                    if(!isVaild){
                        NSOperationQueue.mainQueue().addOperationWithBlock({()-> Void in
                            self.reloadFromOrigin()
                        })
                    }
                })
            }
        }else{
            //ignore it
        }
    }

    /////////////
    func webView(webView: UIWebView,shouldStartLoadWithRequest request: NSURLRequest,navigationType: UIWebViewNavigationType) -> Bool{
        if delegate != nil,let url = request.URL?.description.DecodeURL(){
            return delegate!.webView(self,shouldStartLoadWithRequest: url)
        }
        return true
    }
    @available(iOS 8.0,*)
    func webView(webView: WKWebView,decidePolicyForNavigationAction navigationAction: WKNavigationAction,decisionHandler: (WKNavigationActionPolicy) -> Void){
        var policy = WKNavigationActionPolicy.Allow
        if delegate != nil,let url = navigationAction.request.URL?.debugDescription.DecodeURL(){
            if(!delegate!.webView(self,shouldStartLoadWithRequest: url)){
                policy = WKNavigationActionPolicy.Cancel
            }
        }
        decisionHandler(policy)
    }
    
    //////////////
    func webViewDidStartLoad(webView: UIWebView){
        if delegate != nil{
            delegate?.webViewDidStartLoad(self)
        }
    }
    @available(iOS 8.0,didCommitNavigation navigation: WKNavigation!){
        if delegate != nil{
            delegate?.webViewDidStartLoad(self)
        }
    }
    
    ////////////
    func webViewDidFinishLoad(webView: UIWebView){
        if delegate != nil{
            delegate?.webViewDidFinishLoad(self)
        }
    }
    @available(iOS 8.0,didFinishNavigation navigation: WKNavigation!){
        if delegate != nil{
            delegate?.webViewDidFinishLoad(self)
        }
    }
    //////////////
    func webView(webView: UIWebView,didFailLoadWithError error: NSError?){
        if delegate != nil{
            delegate?.webView(self,didFailLoadWithError: error)
        }
    }
    @available(iOS 8.0,didFailNavigation navigation: WKNavigation!,withError error: NSError){
        if delegate != nil{
            delegate?.webView(self,didFailProvisionalNavigation navigation: WKNavigation!,didFailLoadWithError: error)
        }
    }
    
}

@available(iOS 8.0,*)
extension WKWebView{
    func JavaScriptGet(jscode:String?,NSError?) -> Void)?) -> String?{
        if let js = jscode{
            self.evaluateJavaScript("javascript:" + js,completionHandler: callback)
        }
        return nil
    }
    func runjs(jscode:String?){
        if let js = jscode{
            self.evaluateJavaScript("javascript:" + js,completionHandler: {(error,data) -> Void in
            })
        }
    }
    func getTitle() -> String{
        return self.title == nil ? Strings.empty : self.title!
    }
}

extension UIWebView{
    func JavaScriptGet(jscode:String?) -> String?{
        if let js = jscode{
            return self.stringByEvaluatingJavaScriptFromString("javascript:" + js)
        }
        return nil
    }
    func runjs(jscode:String?){
        if let js = jscode{
            self.stringByEvaluatingJavaScriptFromString("javascript:" + js)
        }
    }
    func getTitle() -> String{
        if let title = stringByEvaluatingJavaScriptFromString("document.title"){
            return title
        }
        return Strings.empty
    }
}

//
//  Processpool.swift
//  iosclient
//
//  Created by Yeshen on 16/9/2.
//  copyright © 2016年 L. All rights reserved.
//

import Foundation
import WebKit

@available(iOS 8.0,*)
class LandowProcesspool {
    
    private var pool:WKProcesspool?
    private var preferences:WKPreferences?
    
    class var ins: Processpool{
        struct Static {
            static var oncetoken:dispatch_once_t = 0
            static var instance:Processpool? = nil
        }
        dispatch_once(&Static.oncetoken){
            Static.instance = Processpool()
        }
        return Static.instance!
    }
    
    func get() -> WKProcesspool{
        if(pool != nil){
            return pool!
        }
        pool = WKProcesspool()
        return pool!
    }
    
    func getPreferences() ->WKPreferences{
        if(preferences != nil){
            return preferences!
        }
        preferences = WKPreferences()
        return preferences!
    }
    
    
}

此外,在Target general 的linked frameworks and libraries中要引入webkit.framework


以上,后面有问题再补充修改

swift(ios) webview 的优化的更多相关文章

  1. 详解如何通过H5(浏览器/WebView/其他)唤起本地app

    这篇文章主要介绍了详解如何通过H5(浏览器/WebView/其他)唤起本地app的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  2. html5录音功能实战示例

    这篇文章主要介绍了html5录音功能实战示例的相关资料,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

  3. HTML5 WebSocket实现点对点聊天的示例代码

    这篇文章主要介绍了HTML5 WebSocket实现点对点聊天的示例代码的相关资料,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧

  4. HTML5页面无缝闪开的问题及解决方案

    这篇文章主要介绍了HTML5页面无缝闪开方案,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下

  5. ios – 在WKWebView中获取链接URL

    我想在WKWebView中获取tapped链接的url.链接采用自定义格式,可触发应用中的某些操作.例如HTTP://我的网站/帮助#深层链接对讲.我这样使用KVO:这在第一次点击链接时效果很好.但是,如果我连续两次点击相同的链接,它将不报告链接点击.是否有解决方法来解决这个问题,以便我可以检测每个点击并获取链接?任何关于这个的指针都会很棒!解决方法像这样更改addobserver在observeValue函数中,您可以获得两个值

  6. ios – 在Swift的UIView中找到UILabel

    我正在尝试在我的UIViewControllers的超级视图中找到我的UILabels.这是我的代码:这是在Objective-C中推荐的方式,但是在Swift中我只得到UIViews和CALayer.我肯定在提供给这个方法的视图中有UILabel.我错过了什么?我的UIViewController中的调用:解决方法使用函数式编程概念可以更轻松地实现这一目标.

  7. ios – 永远不会调用shouldStartLoadWithRequest

    我已经研究和研究,但仍然不明白为什么从未调用过StartLoadWithRequest.我的页面加载正常,并调用了一些UIWebview委托协议方法.请从以下代码中找到相关的摘要:在我的.m中合成我的webview(在头文件中定义):我成功加载了我的webview:把我的代表设置为自己我的所有协议方法都被称为EXCEPTshouldStartLoadWithRequest提前致谢.解决方法尝试在V

  8. ios – 在Swift中将输入字段字符串转换为Int

    所以我非常擅长制作APP广告Swift,我试图在文本字段中做一些非常简单的输入,取值,然后将它们用作Int进行某些计算.但是’vardistance’有些东西不正确它是导致错误的最后一行代码.它说致命错误:无法解开Optional.None解决方法在你的例子中,距离是一个Int?否则称为可选的Int..toInt()返回Int?因为从String到Int的转换可能失败.请参阅以下示例:

  9. 如何在iOS中检测文本(字符串)语言?

    例如,给定以下字符串:我想检测每个声明的字符串中使用的语言.让我们假设已实现函数的签名是:如果没有检测到语言,则返回可选字符串.因此,适当的结果将是:有一个简单的方法来实现它吗?

  10. ios – UIWebView不适合设备屏幕

    我有一个网页视图,我想填写iDevice的全屏.我把它放在视图中心设置为中心并与容器边缘齐平.然而,当我加载应用程序时,视图比它运行的模拟iPhone大.我做了一些搜索,一些建议自动布局,这已经应该是视图的中心.我发现的另一件事是通过代码设置大小.我甚至将应用程序从通用应用程序更改为iPhone,对布局没有影响.完整来源:解决方法设置缩放以适合视图边界.试试这个:希望这可以帮助..:)

随机推荐

  1. Swift UITextField,UITextView,UISegmentedControl,UISwitch

    下面我们通过一个demo来简单的实现下这些控件的功能.首先,我们拖将这几个控件拖到storyboard,并关联上相应的属性和动作.如图:关联上属性和动作后,看看实现的代码:

  2. swift UISlider,UIStepper

    我们用两个label来显示slider和stepper的值.再用张图片来显示改变stepper值的效果.首先,这三个控件需要全局变量声明如下然后,我们对所有的控件做个简单的布局:最后,当slider的值改变时,我们用一个label来显示值的变化,同样,用另一个label来显示stepper值的变化,并改变图片的大小:实现效果如下:

  3. preferredFontForTextStyle字体设置之更改

    即:

  4. Swift没有异常处理,遇到功能性错误怎么办?

    本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请发送邮件至dio@foxmail.com举报,一经查实,本站将立刻删除。

  5. 字典实战和UIKit初探

    ios中数组和字典的应用Applicationschedule类别子项类别名称优先级数据包contactsentertainment接触UIKit学习用Swift调用CocoaTouchimportUIKitletcolors=[]varbackView=UIView(frame:CGRectMake(0.0,0.0,320.0,CGFloat(colors.count*50)))backView

  6. swift语言IOS8开发战记21 Core Data2

    上一话中我们简单地介绍了一些coredata的基本知识,这一话我们通过编程来实现coredata的使用。还记得我们在coredata中定义的那个Model么,上面这段代码会加载这个Model。定义完方法之后,我们对coredata的准备都已经完成了。最后强调一点,coredata并不是数据库,它只是一个框架,协助我们进行数据库操作,它并不关心我们把数据存到哪里。

  7. swift语言IOS8开发战记22 Core Data3

    上一话我们定义了与coredata有关的变量和方法,做足了准备工作,这一话我们来试试能不能成功。首先打开上一话中生成的Info类,在其中引用头文件的地方添加一个@objc,不然后面会报错,我也不知道为什么。

  8. swift实战小程序1天气预报

    在有一定swift基础的情况下,让我们来做一些小程序练练手,今天来试试做一个简单地天气预报。然后在btnpressed方法中依旧增加loadWeather方法.在loadWeather方法中加上信息的显示语句:运行一下看看效果,如图:虽然显示出来了,但是我们的text是可编辑状态的,在storyboard中勾选Editable,再次运行:大功告成,而且现在每次单击按钮,就会重新请求天气情况,大家也来试试吧。

  9. 【iOS学习01】swift ? and !  的学习

    如果不初始化就会报错。

  10. swift语言IOS8开发战记23 Core Data4

    接着我们需要把我们的Rest类变成一个被coredata管理的类,点开Rest类,作如下修改:关键字@NSManaged的作用是与实体中对应的属性通信,BinaryData对应的类型是NSData,CoreData没有布尔属性,只能用0和1来区分。进行如下操作,输入类名:建立好之后因为我们之前写的代码有些地方并不适用于coredata,所以编译器会报错,现在来一一解决。

返回
顶部