UIWebView的那些事

來自何方

根據(jù)類的前綴可以得知,UIWebView是來自于UIKit框架茫蛹,WKWebView來自于WebKit操刀。所以,UIWebVieW和WKWebView的性能差距可想而知婴洼,后來我們會一一道來骨坑。

UIWebView 常用 API分析

-(void)loadRequest:(NSURLRequest *)request;
// 以NSURLRequest的方式加載(一般是NSURL的方式初始化request)。

-(void)loadHTMLString:(NSString *)string baseURL:(nullable NSURL *)baseURL;

// 把HTML轉換成string文本方式加載柬采。

-(void)loadData:(NSData *)data MIMEType:(NSString *)MIMEType textEncodingName:(NSString *)textEncodingName baseURL:(NSURL *)baseURL;

// 以二進制流data的方式加載欢唾。

-(void)reload;             //重新加載當前的界面

-(void)stopLoading;       // 停止加載

-(void)goBack;           // 導航條回退

-(void)goForward;        // 導航條前進

// goBack 和 goForward 類似于UINavagationController 管理的控制器類型(UIViewController)的棧結構執(zhí)行的Push和Pop操作览芳。

- (nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;

//這個方法經常會用到嗤详,script是js腳本,通過script來調起js的方法碗殷。

以下是webView常用的屬性:

- @property (nonatomic, readonly, getter=canGoBack) BOOL canGoBack;   //是否能回退
- @property (nonatomic, readonly, getter=canGoForward) BOOL canGoForward;  // 是否可以前進
- @property (nonatomic, readonly, getter=isLoading) BOOL loading;  // 是否在加載中
- @property (nonatomic) BOOL scalesPageToFit;   // 是否界面是自適應的
- @property (nonatomic) UIDataDetectorTypes dataDetectorTypes NS_AVAILABLE_IOS(3_0); // 設置界面點擊后的類型檢測肩刃。

UIWebViewDelegate 代理

@protocol UIWebViewDelegate

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;

//是否接受這個request的加載請求祟霍,返回布爾值押搪。在此代理中可以通過攔截URL請求,截取request的url的相關屬性值來調起native方法浅碾,native和js協(xié)定好字段的相關邏輯,如果需要調起native方法续语,則需要返回NO垂谢。

-(void)webViewDidStartLoad:(UIWebView *)webView;

//webView開始加載

-(void)webViewDidFinishLoad:(UIWebView *)webView;

//webView加載完畢

-(void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error;

//webView加載失敗

UIWebView native 和 js 的交互策略

  • 最基本的交互方式

native 調起 js (有返回值):

-(nullable NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;

js調用native:

-(BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType;

在這個代理方法中進行處理相關邏輯。

  • iOS7 蘋果對外開放的JavaScriptCore提供的交互方式

JavaScriptCore是webkit的一個重要組成部分疮茄,極大的方便了我們對js的操作滥朱。iOS7以前我們對JS的操作只有webview里面一個函數(shù)stringByEvaluatingJavaScriptFromString,JS對OC的回調都是基于URL的攔截進行的操作力试。

我們要熟悉一下幾個概念:

JSContext

JS執(zhí)行的上下文環(huán)境徙邻,通過JSVirtualMachine管理著所有對象的生命周期,每個JSValue都和JSContext相關聯(lián)并且強引用context畸裳。

JSValue

每個JSValue都是強引用一個context缰犁,OC和JS對象之間的轉換也是通過它,相應的類型轉換如下:
<pre>
@textblock
Objective-C type | JavaScript type
--------------------+---------------------
nil | undefined
NSNull | null
NSString | string
NSNumber | number, boolean
NSDictionary | Object object
NSArray | Array object
NSDate | Date object
NSBlock (1) | Function object (1)
id (2) | Wrapper object (2)
Class (3) | Constructor object (3)
@/textblock
</pre>
JSManagedValue

由于JS內存管理是垃圾回收怖糊,并且JS中的對象都是強引用帅容,而OC是通過引用計數(shù),如果相互強引用的話伍伤,會造成內存泄漏問題并徘,所以用JSManagedValue保存JSValue來避免這種問題的發(fā)生。

JSVirtualMachine

JS運行的虛擬機扰魂,有獨立的堆空間和垃圾回收機制麦乞。

JSExport

一個協(xié)議,如果JS對象想調起native方法劝评,那么native需要自定義一個類來實現(xiàn)這個JSExport協(xié)議就可以了姐直。

介紹過相關基礎類后,來看看調用的例子蒋畜。

@protocol WebViewNativeBridgeDelegete <JSExport>

JSExportAs(add, -(int)add:(int)a other:(int)b);

@end

自定義一個 helper class 實現(xiàn)這個WebViewNativeBridgeDelegete 協(xié)議就可以了简肴。

native 實現(xiàn)這個代理方法

- (int) add: (int)a other: (int)b{
       return a + b;
}  
// js端在調起這個native方法的同時,可以同步拿到返回值百侧。

Note: 在webView加載完畢的時候砰识,要拿到js的上下文。

-(void)webViewDidFinishLoad:(UIWebView *)webView{
   self.context = [webView valueForKeyPath:@"documentView.webView.mainFrame.javaScriptContext"];
   self.context[@"native"] = helper;
}

JSContext 通過evaluateScript 方法實現(xiàn)動態(tài)注入

self.context[@"add"] = ^(NSInteger a, NSInteger b) {
    NSLog(@"sum = %@", @(a + b));
};
[self.context evaluateScript:@"add(2,3);"];

OC call JS

JSValue *value = [self.context[@"add"] callWithArguments:@[@1, @2]];

NSLog(@"value = %@", @([value toInt32]));

UIWebView內存暴增問題的探究

我簡單的寫了一個小界面佣渴,UIWebView加載百度的首頁辫狼,點擊幾個界面后,內存的增長圖如下:

memoryGraph.png

如圖可以看出內存增長的很急辛润,曲線很陡峭膨处,最大達到117.4MB,并且當頁面切換后,內存居高不下真椿,內存無法釋放鹃答。特別如果在設備性能比較差的設備,比如iPhone4突硝,iPhone4s等测摔,很容易觸發(fā)看門狗機制。

為了防止一個應用占用過多的系統(tǒng)資源解恰,開發(fā)iOS的蘋果工程師門設計了一個“看門狗”的機制锋八。在不同的場景下,“看門狗”會監(jiān)測應用的性能护盈。如果超出了該場景所規(guī)定的運行時間挟纱,“看門狗”就會強制終結這個應用的進程。

初學者可能會想著在dealloc中腐宋,設置webView = nil, 可惜根本沒用紊服。
我也google了一下,很多的結果是清除cache胸竞,嘗試過围苫,有效果不過不是讓人滿意的答案,能清除部分的內存撤师,可以參考 這篇文章 剂府。

工欲善其事必先利其器,我們就用Instrument的allocations來檢測一下內存暴增的原因剃盾,很明顯這是系統(tǒng)庫的問題腺占,以圖為證。

allocations.png
majorMemory.png

下圖截取時間跟上圖不一致痒谴,并且在模擬器下操作的衰伯,僅作參考

很明顯50%以上的內存是開辟了一個WebThread(pthread),在這個線程中bitmap的位圖渲染积蔚。由于UIWebView基于UIKit機制意鲸,文本圖片等資源都是在QuartzCore下的context棧中管理,渲染尽爆,繪制怎顾,以及runloop的保持的常駐線程。

UIWebView的內存問題我也無能為力漱贱,可以優(yōu)化的是保持一個UIWebViewController槐雾,持有一個UIWebView屬性,不要在不同的控制器中頻繁的創(chuàng)建幅狮。同時在適當?shù)臅r候進行cache的清空募强,也可以實現(xiàn)NSURLProtocol株灸,進行URL的攔截,使用緩存的圖片資源擎值,避免重復請求慌烧。

不過,我個人推薦使用iOS8引入的WKWebView鸠儿,不過你要想兼容iOS7的話屹蚊,可以做一個兼容性版本,F(xiàn)acebook也引入了捆交,基于WebKit內核的WKWebView,性能會有很大的提升腐巢。UIWebView的內容就寫到這里品追,后續(xù)我會寫下WKWebView。

如果大家對我的理解有什么異議或者有更深的看法肉瓦,歡迎一起交流,謝謝大家胃惜!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市船殉,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌利虫,老刑警劉巖挨厚,帶你破解...
    沈念sama閱讀 218,036評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異糠惫,居然都是意外死亡疫剃,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,046評論 3 395
  • 文/潘曉璐 我一進店門硼讽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來巢价,“玉大人,你說我怎么就攤上這事固阁∪蓝悖” “怎么了?”我有些...
    開封第一講書人閱讀 164,411評論 0 354
  • 文/不壞的土叔 我叫張陵柒爵,是天一觀的道長赚爵。 經常有香客問我法瑟,道長霎挟,這世上最難降的妖魔是什么麻掸? 我笑而不...
    開封第一講書人閱讀 58,622評論 1 293
  • 正文 為了忘掉前任脊奋,我火速辦了婚禮诚隙,結果婚禮上,老公的妹妹穿的比我還像新娘巫延。我一直安慰自己地消,他們只是感情好脉执,可當我...
    茶點故事閱讀 67,661評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著竿开,像睡著了一般玻熙。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上嗦随,一...
    開封第一講書人閱讀 51,521評論 1 304
  • 那天枚尼,我揣著相機與錄音,去河邊找鬼署恍。 笑死,一個胖子當著我的面吹牛袁串,可吹牛的內容都是我干的。 我是一名探鬼主播赎瑰,決...
    沈念sama閱讀 40,288評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼源譬!你這毒婦竟也來了孕似?” 一聲冷哼從身側響起鳞青,我...
    開封第一講書人閱讀 39,200評論 0 276
  • 序言:老撾萬榮一對情侶失蹤臂拓,失蹤者是張志新(化名)和其女友劉穎习寸,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體孵滞,經...
    沈念sama閱讀 45,644評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,837評論 3 336
  • 正文 我和宋清朗相戀三年鸯匹,在試婚紗的時候發(fā)現(xiàn)自己被綠了殴蓬。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,953評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖孤页,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情行施,我是刑警寧澤悲龟,帶...
    沈念sama閱讀 35,673評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站皿渗,受9級特大地震影響轻腺,放射性物質發(fā)生泄漏。R本人自食惡果不足惜挤土,卻給世界環(huán)境...
    茶點故事閱讀 41,281評論 3 329
  • 文/蒙蒙 一仰美、第九天 我趴在偏房一處隱蔽的房頂上張望儿礼。 院中可真熱鬧诉字,春花似錦知纷、人聲如沸冲杀。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,889評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽字币。三九已至共缕,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間翩活,已是汗流浹背便贵。 一陣腳步聲響...
    開封第一講書人閱讀 33,011評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留利耍,地道東北人盔粹。 一個月前我還...
    沈念sama閱讀 48,119評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像轴猎,于是被迫代替她去往敵國和親咬崔。 傳聞我的和親對象是個殘疾皇子烦秩,可洞房花燭夜當晚...
    茶點故事閱讀 44,901評論 2 355

推薦閱讀更多精彩內容

  • 前言 Web 頁面中的 JS 與 iOS Native 如何交互是每個 iOS 猿必須掌握的技能只祠。而說到 Nati...
    幽城88閱讀 2,204評論 1 8
  • 隨著H5技術的興起,在iOS開發(fā)過程中熊杨,難免會遇到原生應用需要和H5頁面交互的問題盗舰。其中會涉及方法調用及參數(shù)傳值等...
    Chris_js閱讀 3,071評論 1 8
  • 本博客主要分以下幾個方面來介紹iOS中的JavaScriptCore JavaScriptCore簡介 JavaS...
    dullgrass閱讀 4,273評論 1 38
  • JavaScriptCore框架主要是用來實現(xiàn)iOS與H5的交互钻趋。由于現(xiàn)在混合編程越來越多,H5的相對講多蛮位,所以研...
    水靈芳蕥閱讀 1,408評論 1 8
  • 本文由我們團隊的 糾結倫 童鞋撰寫。 寫在前面 本篇文章是對我一次組內分享的整理尸曼,大部分圖片都是直接從keynot...
    知識小集閱讀 15,245評論 11 172