當前位置:首頁 » 文件管理 » ios開發webview緩存

ios開發webview緩存

發布時間: 2022-11-20 17:43:49

1. WKWebView網頁緩存刷新問題

在開發過程中遇到前端改變圖片文字,客戶端沒有實時刷新出來,抓包發現也沒有請求網頁相關介面。由於不懂後端的知識,折騰了很久,網上也查找了很多都說需要清除緩存。

這是在網上查找的iOS9以上清除緩存方法

不建議使用上述方法,會浪費用戶流量,除非用戶手動清除緩存。其實主要原因是後端網頁設置的問題,通過head請求獲取介面返回信息如下:

上面標粗的是關鍵,通過測試發現WKWebView是否通過緩存取數據還是重新請求介面取決於 Expires,如上就是緩存時效性是30分鍾,想要實時刷新,可以讓後端不返回這個欄位或者這個過期事件設置短一些,例如1分鍾。建議靜態網頁可以設置長時間,需要實時刷新的建議後端不要設置這個欄位,以免客戶端無法實時顯示。

2. ios 應用刪掉了為什麼webview之前的緩存還存在

瀏覽器緩存機制是指通過HTTP協議頭里的Cache-Control(或Expires)和Last-Modified(或Etag)等欄位來控制文件緩存的機制。這應該是WEB中最早的緩存機制了,是在HTTP協議中實現的,有點不同於DomStorage、AppCache等緩存機制,但本質上是一樣的。可以理解為,一個是協議層實現的,一個是應用層實現的。

Cache-Control用於控制文件在本地緩存有效時長。最常見的,比如伺服器回包:Cache-Control:max-age=600表示文件在本地應該緩存,且有效時長是600秒(從發出請求算起)。在接下來600秒內,如果有請求這個資源,瀏覽器不會發出HTTP請求,而是直接使用本地緩存的文件。

Last-Modified是標識文件在伺服器上的最新更新時間。下次請求時,如果文件緩存過期,瀏覽器通過If-Modified-Since欄位帶上這個時間,發送給伺服器,由伺服器比較時間戳來判斷文件是否有修改。如果沒有修改,伺服器返回304告訴瀏覽器繼續使用緩存;如果有修改,則返回200,同時返回最新的文件。

Cache-Control通常與Last-Modified一起使用。一個用於控制緩存有效時間,一個在緩存失效後,向服務查詢是否有更新。

Cache-Control還有一個同功能的欄位:Expires。Expires的值一個絕對的時間點,如:Expires:Thu,10Nov201508:45:11GMT,表示在這個時間點之前,緩存都是有效的。

Expires是HTTP1.0標准中的欄位,Cache-Control是HTTP1.1標准中新加的欄位,功能一樣,都是控制緩存的有效時間。當這兩個欄位同時出現時,Cache-Control是高優化級的。

Etag也是和Last-Modified一樣,對文件進行標識的欄位。不同的是,Etag的取值是一個對文件進行標識的特徵字串。在向伺服器查詢文件是否有更新時,瀏覽器通過If-None-Match欄位把特徵字串發送給伺服器,由伺服器和文件最新特徵字串進行匹配,來判斷文件是否有更新。沒有更新回包304,有更新回包200。Etag和Last-Modified可根據需求使用一個或兩個同時使用。兩個同時使用時,只要滿足基中一個條件,就認為文件沒有更新。

3. iOS webView利用NSURLProtocol實現離線緩存

        最近公司有一個需求,要對webView(UIWebView)實現緩存機制。即在無網條件下,打開webView頁面,能讀取到網頁,有網情況下,緩存未過期也可以使用本地緩存,加快用戶讀取網頁速度。

        實現緩存策略的方案有很多,為了保證有效,可控等多方面因素,本文採用NSURLProtocol來實現該需求,它的優勢很多,樓主就不再累述了。

        關於NSURLProtocol,網上給出了很多資料,但很多方案都有缺陷,包括github上有star的項目,會遇到在特定情況下,網頁載入不出來的問題,導致一直顯示空白頁。本文成功解決了這些問題,目前該項目已在線上穩定運行。

        寫這篇文章,一方面為了自己,做一些整理,另一方面如果小夥伴,遇到類似需求後,不至於走太多彎路,所謂前人栽樹,後人乘涼。廢話不多說了,直接上內容。

首先關於URL Loading System

簡單來說, URL Loading System 是iOS一系列網路請求類的集合,包括老的NSConnection和現在流行的NSURLSession,還包括一些請求認證的類,一個sessionConfig的類,還有關於處理請求緩存的類等,當然也包括NSURLProtocol類。

當我們需要攔截URL請求時,我們只要通過 - registerClass: 方法注冊我們的NSURLProtocol類,然後去重寫NSURLProtocol類中的方法,就能對我們發起的請求做處理。

NSURLProtocol 是一個抽象類,所以使用的時候必須定義一個它的子類:

需要攔截URL的控制器中注冊該類:

記得在不需要的時候,及時關閉它:

注意一點:如果是基於 NSURLSession 進行的請求,注冊的時候需要注冊到 NSURLSessionConfiguration 中:

注冊成功之後,需要子類CLURLSessionProtocol去實現抽象方法:

+ (BOOL)canInitWithRequest:(NSURLRequest*)request

此處可以攔截需要處理的URL,已經處理過的請求,需要標記請求是否被處理過,防止死循環

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request

這個方法用來統一處理請求 request 對象的,可以修改頭信息,或者重定向。沒有特殊需要,則直接return request;

如果要在這里做重定向以及頭信息的時候注意檢查是否已經添加,因為這個方法可能被調用多次,也可以在後面的方法中做。

+ (BOOL)requestIsCacheEquivalent:(NSURLRequest*)a toRequest:(NSURLRequest*)b

判斷網路請求是否一致,一致的話使用緩存數據。沒需要就調用 super 的方法。

- (void)startLoading

這個方法作用很大,把當前請求的request攔截下來以後,在這個方法裡面對這個request做各種處理,比如添加請求頭,重定向網路,使用自定義的緩存等。

重點:需要標記已經處理過的 request:

- (void)stopLoading

取消流程

流程圖:

4. iOS webView 怎麼緩存

為了保證系統的流暢運行,有一部分運存是被凍結了的:
1、經常從屏幕底部上滑調出快捷欄,點擊一鍵加速;
2、進入騰訊手機管家,點擊空間清理,將系統文件以及緩存垃圾清理一下;
3、將不常用的軟體卸載掉,可以移動的軟體移動到內存卡安裝,盡量釋放系統空間提高穩定度;
4、必要的情況下可以操作清除清除所有數據解決,清除之前記得將手機數據備份好,然後點擊設置--更多設置--恢復出廠設置--清除手機數據。

5. iOS web緩存策略以及手動清除緩存

當我們使用webview載入html資源時,本質上就是向伺服器索取資源的http請求過程,如果我們不注意資源的緩存策略的話,就可能會造成這樣那樣的問題,比如:實時性要求較高的功能卻老是走緩存不更新,有些基本不會變動的頁面卻又每次都重新去伺服器拉請求。

iOS自帶的緩存策略,提供了一個內存和磁碟混合的緩存,一共有7種緩存策略,使用較多的是其中的四種( 下方編號1,2,5,6 )

上面介紹了iOS自帶的緩存控制 NSURLRequestCachePolicy ,也說到當 NSURLRequestCachePolicy 設為默認的 時,主要是根據http的緩存策略來決定是否使用緩存。

那麼就簡單的介紹一下,http的緩存控制和緩存校驗。

在http中,控制緩存開關的欄位有兩個,Pragma和Cache-Control

Pragma有兩個欄位no-cache和expires,當pragma為no-cache時表示禁用緩存,expires的值是一個GMT時間,表示該緩存的有效時間。但是已經被逐步拋棄了,有些網站為了向下兼容還保留了這兩個欄位。

Cache-Control除了在響應中使用,在請求中也可以使用。

在請求中使用,Cache-Control可選的值有:

在響應中使用,Cache-Control可選的值有:

在緩存中,我們需要一個機制來驗證緩存是否有效。比如伺服器的資源更新了,客戶端需要及時刷新緩存;又或者客戶端的資源過了有效期,但伺服器上的資源還是舊的,此時不需要重新發送。緩存校驗就是用來解決這些問題的,在http1.1中,主要關注下 Last-Modified 和 etag 這兩個欄位。

服務端在返回資源時,會將該資源的最後更改時間通過 Last-Modified 欄位返回給客戶端。客戶端下次請求時通過 If-Modified-Since 或者 If-UnModified-Since 帶上 Last-Modified ,服務端檢查該時間是否與伺服器的最後修改時間一致:如果一致,則返回304狀態碼,不反悔資源;如果不一致,則返回200和修改後的資源,並帶上新的時間。

單純的以修改時間來判斷還是有缺陷,比如文件的最後修改時間變了,但內容沒變。對於這樣的情況,我們可以使用etag來處理。
etag的方式是這樣:伺服器通過某個演算法對資源進行計算,取得一串值(類似於文件的md5值),之後將該值通過etag返回給客戶端,客戶端下次請求時通過If-None-Match或If-Match帶上該值,伺服器對該值進行對比校驗:如果一致則不要返回資源。

當我們的webview緩存到一定的峰值的時候,需要手動的清除一下wenview的緩存,方法如下:

找出web緩存的路徑,清空該路徑

webKit除了清除緩存的API

覺得有用,請幫忙點亮紅心

Better Late Than Never!
努力是為了當機會來臨時不會錯失機會。
共勉!

6. iOS wkwebview怎麼寫localStorage

iOS中WKWebView,存在首次載入h5頁面,h5頁面中的js就拿不到localstorage了。

WKWebView localStorage 緩存很嚴重

HTML5在客戶端存儲數據的方式:cookie , localStorage, sessionStorage
cookie:只能存儲少量的數據, 常用來存儲賬號密碼等
localStorage : 沒有時間限制的數據存儲
sessionStorage : 針對一個 session 的數據存儲, 當網頁關閉時,數據也會被刪除。

1.WKWebView設置localStorage
NSString * userContent = [NSString stringWithFormat:@"{"token": "%@", "userId": %@}", @"a1cd4a59-974f-44ab-b264-46400f26c849", @"89"];
// 設置localStorage
NSString *jsString = [NSString stringWithFormat:@"localStorage.setItem('userContent', '%@')", userContent];
// 移除localStorage
// NSString *jsString = @"localStorage.removeItem('userContent')";
// 獲取localStorage
// NSString *jsString = @"localStorage.getItem('userContent')";
[self.webView evaluateJavaScript:jsString completionHandler:nil];

NSString * userContent = @"{"name": "Tom", "age": 10}"];
// 設置localStorage
NSString *jsString = [NSString stringWithFormat:@"localStorage.setItem('userContent', '%@')", userContent];
// 移除localStorage
// NSString *jsString = @"localStorage.removeItem('userContent')";
// 獲取localStorage
// NSString *jsString = @"localStorage.getItem('userContent')";
[self.webView :jsString];
//清理掉所有的localStorage數據
//NSString *clearString = @"localStorage.clear()";

iOS wkwebview localstorage數據處理

WKWebView 在內存佔用上優化的很多。但是在實踐中發現bug:localstorage信息不一致。

A頁面和B頁面都存在 一個WKWebView。 在B頁面使用localstorage保存信息。 回到A頁面取不到最新的數據。

原因:

https://developer.apple.com/reference/webkit/wkwebviewconfiguration 中有個屬性 processPool,描述是:The process pool from which to obtain the view』s Web Content process.

解決方法:

把config中的processPool變為單例共享

}

設置webview的配置 config.processPool = [NYWKWebView singleWkProcessPool];

在查詢資料的過程中,發現了很多Local Storage的缺陷,有一篇關於Local Storage的 論文 可以參考。有以下幾點:

webview 和 iframe 有什麼區別?

webview是網頁的原生載體,用於在原生環境中載入一個頁面,iframe是網頁的html載體,用於在網頁中載入一個頁面

7. [iOS]使用WKWebView遇到的問題總結

在使用WKWebView獲取userAgent的時候, 如果要全局配置, 使所有的WKWebView都能生效, 我們可能的做法是在AppDelegate中來配置, 但是需要一個WKWebView實例對象, 所以可能是這么寫的:

這樣, 你會發現設置一直是無效的, 在回調里列印一下:

這時發現獲取到的 info 欄位為nil, 並且error信息如下:

個人猜測: 這是因為, WKWebView的evaluateJavaScript方法是非同步執行的, 當WKWebView回調這個方法的時候, 其實例對象已經從內存中釋放了, 所以導致回調出錯.
我做了如下驗證, 在回調方法里輸出webView實例對象:

會發現輸出是info有值, 而error為nil, webView有值, 又正常了, 有人說了,看樣子不是這個問題! 真的么? 仔細想一下會發現, 在webView的方法回調閉包里使用了webView實例, 會發生什麼? 對, 循環引用! webView實例此時不為nil, 這也驗證了, 如果webView實例正常的話, 獲取結果是不會有誤的! 繼續上面的驗證, 我們弱引用一下:

這時, 會發現: info和webView都為nil, error值為上面那個錯誤!!!

這樣, 基本驗證出現這個問題的原因是: webView 提前釋放了!

但是為了添加這個設置, 而將webView 設為全局變數, 彷彿有點得不償失, 這時可以在使用webView的頁面進行設置, 或者使用UIWebView替換:

在做JS與原生交互的時候, 使用下面方法注入的協議無效:

然後在js端使用的時候: 這里不需要傳參數, 直接這么寫的

這樣, 沒有響應js端的事件!!!
在代理方法中:

一直沒有收到回調!!!
其實, 並不是注入協議失敗, 這么使用也沒問題, 問題就出在postMessage的參數上, 如果是帶參數的:

這么寫, 是完全沒有問題的, 所以如果不需傳參數的話, 可以這么寫:

給一個空的字典, 就能正常交互了!!!

在WKWebView載入的HTML頁面上, 如果長按會彈出一些選擇框, 在文字上長按, 會彈出UIMenuController選擇框:

而在圖片上長按, 會彈出一個alertSheet:

這里可以保存圖片到系統相冊(如果有許可權), 或者復制到剪切板. 但是這些需求並不是我們需要, 如何禁止這些行為呢?需要從JS入手, 只需要執行下面兩句js即可:

可以在創建WKWebView的時候注入:

也可以在頁面載入完成後的代理方法中執行:

在載入的HTML頁面中, 無端出現一個廣告的懸浮框:

打開之後是這樣的:

而且只會在移動4G網路下才會出現, 其實這是移動的流量劫持, 強加的廣告推廣,目前網上有一些解決方式,常用的有:

其他的可參考這篇文章 iOS 客戶端對於運營商劫持的一點點對抗方式


在聯調的時候, 前端的同學改了一些東西, 例如頁面的布局, 顯示元素, 或者js方法, 而APP端沒反應!!!

這是因為, WKWebView有緩存, 為了保證每次載入的都是最新的頁面, 可以在載入的鏈接後面加上一個時間戳, 例如你的HTML地址為:

一般使用是這樣的:

這樣的話是有緩存, 載入一次之後, 再去載入也不是最新的頁面, 可以這樣使用:

這樣每次載入的時候都會是最新的, 當然弊端就是, 每次都會耗費一些額外的流量.

在頁面無導航的情況下,系統會自動調節滾動視圖的contentInset,使其視圖永遠處於狀態欄之下,但是如果我們想讓滾動視圖的Y坐標從屏幕頂端(狀態欄)開始,我們都知道怎麼修改,但是 WKWebView不是繼承自UIScrollView 的,所以不能直接設置,可以這么寫:

這個閃退發生在與 JS 進行交互,使用下面的方法注冊協議時:

如果重復注冊了相同名稱的協議,就會發生閃退,所以在使用完webView的時候,一定要記得移除已注冊的協議:

app首頁使用 WKWebView 來承載的內容,在啟動時,如果添加了引導頁/廣告頁,這時如果有手勢操作,例如在出現廣告頁時點擊屏幕,就會閃退,並在控制台輸出:

添加一個全局斷點,調試發現崩潰信息為

查了些資料,沒找到具體原因,但是了解到和 +load方法有關,我是在 +load 方法內初始化的廣告頁的信息,把這些放在 didFinishLaunchingWithOptions 進行初始化,就不會有這個問題;

解決:
將廣告/引導頁視圖的初始化放在 didFinishLaunchingWithOptions 方法內。

8. iOS的webView如何實現html的離線緩存

這個實現難點在緩存圖片上。html代碼的緩存對你來說不是問題吧。基於這個前提,
下面這個方案是我自己做的,也具體在項目實現了。思路是這樣的:
第1步、先獲取html頁面里所有圖片地址。
方法一:離線獲取獲取到html代碼。html代碼你可以把他理解成是一個很長的字元串。通過正則表達式把這個html頁面里的所有img標簽url。如果是相對url,就加上host。如果是絕對url,就直接下載。這樣這個頁面里的所有圖片路徑都拿到了。
方法一的獲取img標簽url的正則表達式:
NSString *urlPattern = @"<img[^>]+?src=[\"']?([^>'\"]+)[\"']?";

方法二:通過webview和js 本地程序的交換,獲取到html頁面所有圖片下載地址。

9. ios uiwebview 緩存文件在哪

順便說下NSURLRequest對象,它有個cachePolicy屬性,只要其值為的話,就不會訪問緩存。可喜的是這種情況貌似只有在緩存里沒取到,或是強制刷新時才可能出現。
實際上NSURLCache本身就有磁碟緩存功能,然而在iOS上,NSCachedURLResponse卻被限制為不能緩存到磁碟(NSURLCacheStorageAllowed被視為)。
不過既然知道了原理,那麼只要自己實現一個NSURLCache的子類,然後改寫cachedResponseForRequest:方法,讓它從硬碟讀取緩存即可。

於是就開工吧。這次的demo邏輯比較復雜,因此我就按步驟來說明了。

先定義視圖和控制器。
它的邏輯是打開應用時就嘗試訪問緩存文件,如果發現存在,則顯示緩存完畢;否則就嘗試下載整個網頁的資源;在下載完成後,也顯示緩存完畢。
不過下載所有資源需要解析HTML,甚至是JavaScript和CSS。為了簡化我就直接用一個不顯示的UIWebView載入這個頁面,讓它自動去發起所有請求。
當然,緩存完了還需要觸發事件來顯示網頁。於是再提供一個按鈕,點擊時顯示緩存的網頁,再次點擊就關閉。
順帶一提,我本來想用Google為例的,可惜它自己實現了HTML 5離線瀏覽,也就體現不出這種方法的意義了,於是只好拿網路來墊背。
Objective-c代碼 收藏代碼
#import <UIKit/UIKit.h>

@interface WebViewController : UIViewController <UIWebViewDelegate> {
UIWebView *web;
UILabel *label;
}

@property (nonatomic, retain) UIWebView *web;
@property (nonatomic, retain) UILabel *label;

- (IBAction)click;

@end

#import "WebViewController.h"
#import "URLCache.h"

@implementation WebViewController

@synthesize web, label;

- (IBAction)click {
if (web) {
[web removeFromSuperview];
self.web = nil;
} else {
CGRect frame = {{0, 0}, {320, 380}};
UIWebView *webview = [[UIWebView alloc] initWithFrame:frame];
webview.scalesPageToFit = YES;
self.web = webview;

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www..com/"]];
[webview loadRequest:request];
[self.view addSubview:webview];
[webview release];
}
}

- (void)addButton {
CGRect frame = {{130, 400}, {60, 30}};
UIButton *button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
button.frame = frame;
[button addTarget:self action:@selector(click) forControlEvents:UIControlEventTouchUpInside];
[button setTitle:@"我點" forState:UIControlStateNormal];
[self.view addSubview:button];
}

- (void)viewDidLoad {
[super viewDidLoad];

URLCache *sharedCache = [[URLCache alloc] initWithMemoryCapacity:1024 * 1024 diskCapacity:0 diskPath:nil];
[NSURLCache setSharedURLCache:sharedCache];

CGRect frame = {{60, 200}, {200, 30}};
UILabel *textLabel = [[UILabel alloc] initWithFrame:frame];
textLabel.textAlignment = UITextAlignmentCenter;
[self.view addSubview:textLabel];
self.label = textLabel;

if (![sharedCache.responsesInfo count]) { // not cached
textLabel.text = @"緩存中…";

CGRect frame = {{0, 0}, {320, 380}};
UIWebView *webview = [[UIWebView alloc] initWithFrame:frame];
webview.delegate = self;
self.web = webview;

NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://www..com/"]];
[webview loadRequest:request];
[webview release];
} else {
textLabel.text = @"已從硬碟讀取緩存";
[self addButton];
}

[sharedCache release];
}

- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
self.web = nil;
label.text = @"請接通網路再運行本應用";
}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
self.web = nil;
label.text = @"緩存完畢";
[self addButton];

URLCache *sharedCache = (URLCache *)[NSURLCache sharedURLCache];
[sharedCache saveInfo];
}

- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];

if (!web) {
URLCache *sharedCache = (URLCache *)[NSURLCache sharedURLCache];
[sharedCache removeAllCachedResponses];
}
}

- (void)viewDidUnload {
self.web = nil;
self.label = nil;
}

- (void)dealloc {
[super dealloc];
[web release];
[label release];
}

@end

10. ios wkwebview 是否有緩存

有緩存的
如果清理緩存
- (void)dealloc {
[self.webView removeObserver:self forKeyPath:@"estimatedProgress"];
[self.webView removeObserver:self forKeyPath:@"title"];
[self clearCache];
}

/** 清理緩存的方法,這個方法會清除緩存類型為HTML類型的文件*/
- (void)clearCache {
/* 取得Library文件夾的位置*/
NSString *libraryDir = (NSLibraryDirectory,NSUserDomainMask, YES)[0];
/* 取得bundle id,用作文件拼接用*/
NSString *bundleId = [[[NSBundle mainBundle] infoDictionary]objectForKey:@"CFBundleIdentifier"];
/*
* 拼接緩存地址,具體目錄為App/Library/Caches/你的APPBundleID/fsCachedData
*/
NSString *webKitFolderInCachesfs = [NSString stringWithFormat:@"%@/Caches/%@/fsCachedData",libraryDir,bundleId];

NSError *error;
/* 取得目錄下所有的文件,取得文件數組*/
NSFileManager *fileManager = [NSFileManager defaultManager];
// NSArray *fileList = [[NSArray alloc] init];
//fileList便是包含有該文件夾下所有文件的文件名及文件夾名的數組
NSArray *fileList = [fileManager contentsOfDirectoryAtPath:webKitFolderInCachesfs error:&error];
/* 遍歷文件組成的數組*/
for(NSString * fileName in fileList){
/* 定位每個文件的位置*/
NSString * path = [[NSBundle bundleWithPath:webKitFolderInCachesfs] pathForResource:fileName ofType:@""];
/* 將文件轉換為NSData類型的數據*/
NSData * fileData = [NSData dataWithContentsOfFile:path];
/* 如果FileData的長度大於2,說明FileData不為空*/
if(fileData.length >2){
/* 創建兩個用於顯示文件類型的變數*/
int char1 =0;
int char2 =0;

[fileData getBytes:&char1 range:NSMakeRange(0,1)];
[fileData getBytes:&char2 range:NSMakeRange(1,1)];
/* 拼接兩個變數*/
NSString *numStr = [NSString stringWithFormat:@"%i%i",char1,char2];
/* 如果該文件前四個字元是6033,說明是Html文件,刪除掉本地的緩存*/
if([numStr isEqualToString:@"6033"]){
[[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@/%@",webKitFolderInCachesfs,fileName]error:&error];
continue;
}
}
}
}

熱點內容
下沉演算法 發布:2024-10-05 21:59:43 瀏覽:995
資料庫管理系統的開發 發布:2024-10-05 21:58:02 瀏覽:139
人員最低配置方案怎麼寫 發布:2024-10-05 21:56:26 瀏覽:765
智邦國際伺服器ip 發布:2024-10-05 21:47:37 瀏覽:596
python英文怎麼讀 發布:2024-10-05 21:47:02 瀏覽:145
魔獸世界退役伺服器有什麼用處 發布:2024-10-05 20:50:00 瀏覽:195
新車配置不符怎麼投訴 發布:2024-10-05 20:49:00 瀏覽:389
編譯的html文件 發布:2024-10-05 20:48:58 瀏覽:161
python自學網站 發布:2024-10-05 20:46:08 瀏覽:19
存儲在rom中的數據當計算機斷電後 發布:2024-10-05 20:43:46 瀏覽:10