iOSUIWebView---快停下啦,你的愚蠢的行為
公元前
之前還是學生時代的時候給社團們學弟學妹們介紹iOS編程的時候,簡單的準備了圖靈ios培訓第一周(使用UIWebView創建簡易瀏覽器),
NSURL *url =[NSURL URLWithString:urlString];
NSLog(urlString);
NSURLRequest *request =[NSURLRequest requestWithURL:url];
[webView loadRequest:request];
運用的就是上面的這樣的三行代碼搞定一切的網頁載入的方法。
公元後
後來在項目中遇到了使用UIWebView控件時,理所當然的愚蠢的
用了裏面的方法完畢了Boss的需求,但後期測試的時候,在腎4上
以及用Charles工具模擬慢網速的時候發現這樣做的用戶體驗不太
好,基本的問題就是當該網頁內容許多的時候,在2G網絡和移
動3G網絡的時候,出現載入太慢。出現卡頓的現象。甚至在舊機
器上會出現崩潰的現象。
分析一下原因,主要由下面幾種原因:
1.舊的手機CPU性能內存較差。一下占用率太高。(PS:後來
iOS8之後蘋果出了新的WebKit框架WKWebKit,性能提升了不
少,建議不須要適配iOS8下面的能夠考慮嘗試)
2.頁面內容較多,數據量龐大,即使是新款手機也扛不住呀(最
典型的應該是天貓商城App的首頁啦,下拉了幾分鐘還沒有到達盡
頭,一下子載入所有數據。手機肯定扛不住呀)
3. 運用上面那種人人都會的沒技術含量的代碼是在主線程裏面進
行的,數據量大。網速不行,會一值在載入,影響用戶進行其它
操作
那如何解決上邊的問題呢?
換手機?別逗了一個腎機依然那麽貴,NO Pass
載入頁面的時候做上緩存,甚至分段的展示數據(先僅僅載入一部分數據。隨著用戶下拉再逐步載入)
既然操心數據量多造成在主線程調用會卡死,那就想想辦法另外開辟線程載入數據。
權衡之後
上邊的代碼方法是萬萬行不通的最經常使用的還是想想辦法另辟蹊徑的開辟新航線:
這裏我們能夠用到經常使用多線程四種方法中的一種:
NSOperationQueue 操作隊列中進行編程
1.創建一個隊列並初始化:
static NSOperationQueue *queue;
queue=[[NSOperationQueue alloc]init];
2.創建操作對象並封裝要運行的任務
NSInvocationOperation *op=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downLoadWeb) object:nil];
將對象加入到隊列中
[queue addOperation:op];
3.開辟一個新的線程,實現運行的任務,獲取從server上載入的數據,並存儲在NSData中
-(void)downLoadWeb
{
NSURL *url=[NSURL URLWithString:@"http://·········.php"];
NSError *error;
NSString *strData=[NSString stringWithContentsOfURL:url encoding:NSUTF8StringEncoding error:&error];
NSData *data=[strData dataUsingEncoding:NSUTF8StringEncoding];
if (data !=nil) {
[self performSelectorOnMainThread:@selector(downLoad_completed:) withObject:data waitUntilDone:NO];
}
else
{
NSLog(@"error when download:%@",error);
}
}
4.推斷從server中正確的獲得數據後,再返回主線程中進行數據的載入(為啥要返回主線程,由於蘋果規定數據載入到控件上必須在主線程上進行,防止多個線程改動控件引發崩潰和莫名其妙的問題)
-(void)downLoad_completed:(NSData *)data
{
NSURL *url=[NSURL URLWithString:@"http://·········.php"];
NSString *nameType=[self mimeType:url];
NSLog(@"%@",nameType);
[webView loadData:data MIMEType:nameType textEncodingName:@"UTF-8" baseURL:url];
}
上面中用到了UIWebView的
loadData:<#(nonnull NSData *)#> MIMEType:<#(nonnull NSString *)#> textEncodingName:<#(nonnull NSString *)#> baseURL:<#(nonnull NSURL *)#>
//第一個誒參數是一個NSData
//第二個參數是MIMEType
//第三個參數是編碼格式
//第四個相對地址。
當中第二參數須要調用一下下面方法,獲取指定URL的MIMEType類型
#pragma mark 獲取指定URL的MIMEType類型
- (NSString *)mimeType:(NSURL *)url
{
NSURLRequest *request = [NSURLRequest requestWithURL:url];
//使用同步方法後去MIMEType
NSURLResponse *response = nil;
[NSURLConnection sendSynchronousRequest:request returningResponse:&response error:nil];
return response.MIMEType;
}
這裏返回的是text/html
第四個參數是傳的URL的地址。當時我嘗試著賦值nil後發現網頁裏面的圖片就不能正確的顯示出來
好了。介紹好了步驟後反思一下為什麽這麽做比較好的用戶體驗
1.首先我們運用了多線程載入數據。不影響用戶操作其它數據
我還有益調皮的在downLoadWeb中加上下面的代碼:
for (int i=1; i<100000000; i++) {
NSLog(@"我卡到你了嗎?");
}
測試結果全然不影響用戶操作其它地方。要是按原始的三行代
碼搞定UIWebView就會出現一直卡的悲催體驗。
2.我們先在子線程中把數據載入到NSData中,再 通過loadData:函
數進行載入,相當於進行了本地數據的讀取操作。本地讀取的速
度是遠遠大於網絡獲取的。
3.對於網頁數據基本保持不變的,我們全然能夠 用數據庫存儲
NSData裏面的數據,下次進入免去了下載的過 程。
這在三行代碼
的方法是全然行不通的。
iOSUIWebView---快停下啦,你的愚蠢的行為