最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

iOS開發(fā)WebViewJavascriptBridge通訊原理解析

 更新時間:2022年11月23日 11:23:50   作者:好_好先生  
這篇文章主要為大家介紹了iOS開發(fā)WebViewJavascriptBridge通訊原理示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

前言

H5頁面具有跨平臺、開發(fā)容易、上線不需要跟隨App的版本等優(yōu)點,但H5頁面也有體驗不如native好、沒有native穩(wěn)定等問題。所以目前大部分App都是使用Hybrid混合開發(fā)的。

當然有了H5頁面就少不了H5與native交互,交互就會用到bridge的能力了。

WebViewJavascriptBridge是一個native與JS進行消息互通的第三方庫,本章會簡單解析一下WebViewJavascriptBridge的源碼和實現(xiàn)原理。

通訊原理

JavaScriptCore

JavaScriptCore作為iOS的JS引擎為原生編程語言OC、Swift 提供調用 JS 程序的動態(tài)能力,還能為 JS 提供原生能力來彌補前端所缺能力。 iOS中與JS通訊使用的是JavaScriptCore庫,正是因為JavaScriptCore這種起到的橋梁作用,所以也出現(xiàn)了很多使用JavaScriptCore開發(fā)App的框架,比如RN、Weex、小程序、Webview Hybrid等框架。 如圖:

當然JS引擎不光有蘋果的JavaScriptCore,谷歌有V8引擎、Mozilla有SpiderMoney

JavaScriptCore本章只簡單介紹,后面主要解析WebViewJavascriptBridge。因為uiwebview已經(jīng)不再使用了,所以后面提到的webview都是wkwebview,demo也是以wkwebview進行解析。

源碼解析

代碼結構

除了引擎層外,還需要native、h5和WebViewJavascriptBridge三層才能完成一整個信息通路。WebViewJavascriptBridge就是中間那個負責通信的SDK。

WebViewJavascriptBridge的核心類主要包含幾個:

  • WebViewJavascriptBridge_JS:是一個JS的字符串,作用是JS環(huán)境的Bridge初始化和處理。負責接收native發(fā)給JS的消息,并且把JS環(huán)境的消息發(fā)送給native。
  • WKWebViewJavascriptBridge/WebViewJavascriptBridge:主要負責WKWebView和UIWebView相關環(huán)境的處理,并且把native環(huán)境的消息發(fā)送給JS環(huán)境。
  • WebViewJavascriptBridgeBase:主要實現(xiàn)了native環(huán)境的Bridge初始化和處理。

初始化

WebViewJavascriptBridge是如何完成初始化的呢,首先要有webview容器,所以要對webview容器進行初始化,設置代理,初始化WebViewJavascriptBridge對象,加載URL。

    WKWebView* webView = [[NSClassFromString(@"WKWebView") alloc] initWithFrame:self.view.bounds];
    webView.navigationDelegate = self;
    [self.view addSubview:webView];
    // 開啟打印
    [WebViewJavascriptBridge enableLogging];
    // 創(chuàng)建bridge對象
    _bridge = [WebViewJavascriptBridge bridgeForWebView:webView];
    // 設置代理
    [_bridge setWebViewDelegate:self];

這里加載的就是JSBridgeDemoApp這個本地的html文件。

    NSString* htmlPath = [[NSBundle mainBundle] pathForResource:@"JSBridgeDemoApp" ofType:@"html"];
    NSString* appHtml = [NSString stringWithContentsOfFile:htmlPath encoding:NSUTF8StringEncoding error:nil];
    NSURL *baseURL = [NSURL fileURLWithPath:htmlPath];
    [webView loadHTMLString:appHtml baseURL:baseURL];

再看一下JSBridgeDemoApp這個html文件。

function setupWebViewJavascriptBridge(callback) {
// 第一次調用這個方法的時候,為false
    if (window.WebViewJavascriptBridge) { return callback(WebViewJavascriptBridge); }
// 第一次調用的時候,為false
    if (window.WVJBCallbacks) { return window.WVJBCallbacks.push(callback); }
// 把callback對象賦值給對象
    window.WVJBCallbacks = [callback];
// 加載WebViewJavascriptBridge_JS中的代碼
// 相當于實現(xiàn)了一個到https://__bridge_loaded__的跳轉
    var WVJBIframe = document.createElement('iframe');
    WVJBIframe.style.display = 'none';
    WVJBIframe.src = 'https://__bridge_loaded__';
    document.documentElement.appendChild(WVJBIframe);
    setTimeout(function() { document.documentElement.removeChild(WVJBIframe) }, 0)
    }
// 驅動所有hander的初始化
setupWebViewJavascriptBridge(function(bridge) {
...
}

在JSBridgeDemoApp的script標簽下,聲明了一個名為setupWebViewJavascriptBridge的方法,在加載html后直接進行了調用。 setupWebViewJavascriptBridge方法中最核心的代碼是:

創(chuàng)建一個iframe標簽,然后加載了鏈接為 https://bridge_loaded 的內容。相當于在當前頁面內容實現(xiàn)了一個到 https://bridge_loaded 的內部跳轉。 ps:iframe標簽用于在網(wǎng)頁內顯示網(wǎng)頁,也使用iframe作為鏈接的目標。

html文件內部實現(xiàn)了這個跳轉后native端是如何監(jiān)聽的呢,在webview的代理里有一個方法:decidePolicyForNavigationAction 這個代理方法的作用是只要有webview跳轉,就會調用到這個方法。代碼如下:

// 只要webview有跳轉,就會調用webview的這個代理方法
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler {
    if (webView != _webView) { return; }
    NSURL *url = navigationAction.request.URL;
    __strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate;
    // 如果是WebViewJavascriptBridge發(fā)送或者接收消息,則特殊處理。否則按照正常流程處理
    if ([_base isWebViewJavascriptBridgeURL:url]) {
        if ([_base isBridgeLoadedURL:url]) {
            // 是否是 https://__bridge_loaded__ 這種初始化加載消息
            [_base injectJavascriptFile];
        } else if ([_base isQueueMessageURL:url]) {
            // https://__wvjb_queue_message__
            // 處理WEB發(fā)過來的消息
            [self WKFlushMessageQueue];
        } else {
            [_base logUnkownMessage:url];
        }
        decisionHandler(WKNavigationActionPolicyCancel);
        return;
    }
    // webview的正常代理執(zhí)行流程
...

從上面的代碼中可以看到,如果監(jiān)聽的webview跳轉不是WebViewJavascriptBridge發(fā)送或者接收消息就正常執(zhí)行流程,如果是WebViewJavascriptBridge發(fā)送或者接收消息則對此攔截不跳轉,并且針對消息進行處理。 當消息url是https://bridge_loaded 的時候,會去注入WebViewJavascriptBridge_js到JS中:

// 將WebViewJavascriptBrige_JS中的方法注入到webview中并且執(zhí)行
- (void)injectJavascriptFile {
    NSString *js = WebViewJavascriptBridge_js();
    // 把javascript代碼注入webview中執(zhí)行
    [self _evaluateJavascript:js];
    // javascript環(huán)境初始化完成以后,如果有startupMessageQueue消息,則立即發(fā)送消息
    if (self.startupMessageQueue) {
        NSArray* queue = self.startupMessageQueue;
        self.startupMessageQueue = nil;
        for (id queuedMessage in queue) {
            [self _dispatchMessage:queuedMessage];
        }
    }
}

[self _evaluateJavascript:js];就是執(zhí)行webview中的evaluateJavaScript:方法。把JS寫入webview。所以執(zhí)行完此處代碼JS當中就有bridge這個對象了。初始化完成。

總結:在加載h5頁面后會調用setupWebViewJavascriptBridge方法,該方法內創(chuàng)建了一個iframe加載內容為 https://bridge_loaded ,該消息被decidePolicyForNavigationAction監(jiān)聽到,然后執(zhí)行injectJavascriptFile去讀取WebViewJavascriptBridge_js將WebViewJavascriptBridge對象注入到當前h5中。

WebViewJavascriptBridge 對象

整個WebViewJavascriptBridge_js文件其實就是一個字符串形式的js代碼,里面包含WebViewJavascriptBridge和相關bridge調用的方法。

// 初始化Bridge對象,OC可以通過WebViewJavascriptBridge來調用JS里面的各種方法
window.WebViewJavascriptBridge = {
    registerHandler: registerHandler, // JS中注冊方法
    callHandler: callHandler, // JS中調用OC的方法
    disableJavscriptAlertBoxSafetyTimeout: disableJavscriptAlertBoxSafetyTimeout,
    _fetchQueue: _fetchQueue, // 把消息轉換成JSON串
    _handleMessageFromObjC: _handleMessageFromObjC // OC調用JS的入口方法
};

WebViewJavascriptBridge對象里核心的方法有:

  • registerHandler:JS中注冊方法
  • callHandler: JS中調用native的方法
  • _fetchQueue: 把消息轉換成JSON字符串
  • _handleMessageFromObjC:native調用JS的入口方法

當初始化完成后,WebViewJavascriptBridge對象和對象里的方法就已經(jīng)存在并且可用了。

JS和native是如何相互傳遞消息的呢?從上面的代碼中可以看到如果JS想要發(fā)送消息給native就會調用callHandler方法;如果native想要調用JS方法那JS側就必須先注冊一個registerHandler方法。

相對應的我們看一下native側是如何與JS傳遞消息的,其實接口標準是一致的,native調JS的方法使用callHandler方法:

id data = @{ @"dataFromOC": @"aaaa!" };
    [_bridge callHandler:@"OCToJSHandler" data:data responseCallback:^(id response) {
        NSLog(@"JS回調的數(shù)據(jù)是:%@", response);
    }];

JS調native方法在native側就必須先注冊一個registerHandler方法:

    // 注冊事件(h5調App)
    [_bridge registerHandler:@"JSTOOCCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
        NSLog(@"JSTOOCCallback called: %@", data);
        responseCallback(@"Response from JSTOOCCallback");
    }];

也就是說native像JS發(fā)送消息的話,JS側要先注冊該方法registerHandler,native側調用callHandler; JS像native發(fā)送消息的話,native側要先注冊registerHandler,JS側調用callHandler。這樣才能完成雙端通信。

如圖:

native向JS發(fā)送消息

現(xiàn)在要從native側向JS側發(fā)送一條消息,方法名為:"OCToJSHandler",并且拿到JS的回調,具體實現(xiàn)細節(jié)如下:

JS側

native向JS發(fā)送數(shù)據(jù),首先要在JS側去注冊這個方法:

bridge.registerHandler('OCToJSHandler', function(data, responseCallback) {
    ...
})

這個registerHandler的實現(xiàn)在WebViewJavascriptBridge_JS是:

// web端注冊一個消息方法,將注冊的方法存儲起來
function registerHandler(handlerName, handler) {
    messageHandlers[handlerName] = handler;
}

就是將這個注冊的方法存儲到messageHandlers這個map中,key為方法名稱,value為function(data, responseCallback) {}這個方法。

native側

native側調用bridge的callHandler方法,傳參為data和一個callback回調

id data = @{ @"dataFromOC": @"aaaa!" };
[_bridge callHandler:@"OCToJSHandler" data:data responseCallback:^(id response) {
    NSLog(@"JS回調的數(shù)據(jù)是:%@", response);
}];

接下來會走到WebViewJavascriptBridgeBase的-sendData: responseCallback: handlerName:方法,該方法中將"data"和"handlerName"存入到一個message字典中,如果存在callback會生成一個callbackId一并存入到message字典中,并且將該回調存入到responseCallbacks中,key為callbackId,value為這個callback。代碼如下:

// 所有信息存入字典
NSMutableDictionary* message = [NSMutableDictionary dictionary];
if (data) {
    message[@"data"] = data;
}
if (responseCallback) {
    NSString* callbackId = [NSString stringWithFormat:@"objc_cb_%ld", ++_uniqueId];
    self.responseCallbacks[callbackId] = [responseCallback copy];
    message[@"callbackId"] = callbackId;
}
if (handlerName) {
    message[@"handlerName"] = handlerName;
}
[self _queueMessage:message];

將message存儲到隊列等待執(zhí)行,執(zhí)行該條message時會先將message進行序列化,序列化完成后將message拼接到字符串WebViewJavascriptBridge._handleMessageFromObjC('%@');中,然后執(zhí)行_evaluateJavascript執(zhí)行該js方法。

// 把OC消息序列化、并且轉化為JS環(huán)境的格式,然后在主線程中調用_evaluateJavascript
- (void)_dispatchMessage:(WVJBMessage*)message {
    NSString *messageJSON = [self _serializeMessage:message pretty:NO];
    NSString* javascriptCommand = [NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON];
    [self _evaluateJavascript:javascriptCommand];
}

_handleMessageFromObjC方法會將messageJSON傳遞給_dispatchMessageFromObjC進行處理。 首先將messageJSON進行解析,根據(jù)handlerName取出存儲在messageHandlers中的方法。如果該message中存在callbackId,將callbackId作為參數(shù)生成一個回調放到responseCallback中。 代碼如下:

function _doDispatchMessageFromObjC() {
// 解析發(fā)送過來的JSON
    var message = JSON.parse(messageJSON);
    var messageHandler;
    var responseCallback;
    // 主動調用
    // 如果有callbackid
    if (message.callbackId) {
    // 將callbackid當做callbackResponseId再返回回去
        var callbackResponseId = message.callbackId;
        responseCallback = function(responseData) {
        // 把消息從JS發(fā)送到OC,執(zhí)行具體的發(fā)送操作
            _doSend({ handlerName:message.handlerName, responseId:callbackResponseId, responseData:responseData });
            };
        // 獲取JS注冊的函數(shù),取出消息里的handlerName
        var handler = messageHandlers[message.handlerName];
        // 調用JS中的對應函數(shù)處理
        handler(message.data, responseCallback);
            }
    }

handler方法其實就是名為"OCToJSHandler"的方法,這時就走到了registerHandler里的那個function(data, responseCallback) {}方法了。我們看一下方法內部的具體實現(xiàn):

bridge.registerHandler('OCToJSHandler', function(data, responseCallback) {
    // OC中傳過來的數(shù)據(jù)
    log('從OC傳過來的數(shù)據(jù)是:', data)
    // JS返回數(shù)據(jù)
    var responseData = { 'dataFromJS':'bbbb!' }
    responseCallback(responseData)
})

data就是從native傳過來的數(shù)據(jù),responseCallback就是保存的回調,然后又生成了新數(shù)據(jù)作為參數(shù)給到了這個回調。

responseCallback的實現(xiàn)是:

responseCallback = function(responseData) {
    // 把消息從JS發(fā)送到OC,執(zhí)行具體的發(fā)送操作
    _doSend({ handlerName:message.handlerName, responseId:callbackResponseId, responseData:responseData });
};

將該方法的handlerName、生成的callbackResponseId(也就是callbackId)以及JS返回的數(shù)據(jù)一起給到_doSend方法。

_doSend方法將message存儲到sendMessageQueue消息列表中,并使用messagingIframe加載了一次https://wvjb_queue_message。

// 把消息從JS發(fā)送到OC,執(zhí)行具體的發(fā)送操作
    function _doSend(message, responseCallback) {
    // 把消息放入消息列表
    sendMessageQueue.push(message);
    // 發(fā)出js對oc的調用,讓webview執(zhí)行跳轉操作,可以在decidePolicyForNavigationAction:中攔截到js發(fā)給oc的消息
    messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE;
    }

這時webview的監(jiān)聽方法decidePolicyForNavigationAction監(jiān)聽到了https://wvjb_queue_message 消息后還是執(zhí)行WebViewJavascriptBridge._fetchQueue()去取數(shù)據(jù),取到數(shù)據(jù)后根據(jù)responseId當初在_responseCallbacks中存儲的callback,然后執(zhí)行callback、移除responseCallbacks中的數(shù)據(jù)。到此為止,整個native向JS發(fā)送消息的過程就完成了。

總結:

  • JS中先調用registerHandler將方法存儲到messageHandlers中
  • native調用callHandler:方法,將消息內容存儲到message中,回調存儲到responseCallbacks中。
  • 將message消息序列化通過_evaluateJavascript方法執(zhí)行_handleMessageFromObjC
  • 將message解析,通過message.handlerName從messageHandlers取出該方法;根據(jù)message.callbackId生成回調
  • 執(zhí)行該方法,回調

JS向native發(fā)送消息

從JS向native發(fā)消息其實和native向JS發(fā)消息的接口層面是差不多的。

native側

native側首先要注冊一個JSTOOCCallback方法

[_bridge registerHandler:@"JSTOOCCallback" handler:^(id data, WVJBResponseCallback responseCallback) {
    responseCallback(@"Response from JSTOOCCallback");
}];

該方法也同樣是將該方法的callback存儲起來,存儲到messageHandlers當中,key就是方法名"JSTOOCCallback",value就是callback。

JS側

JS側會調用callHandler方法:

// 調用oc中注冊的那個方法
bridge.callHandler('JSTOOCCallback', {'foo': 'bar'}, function(response) {
    log('JS 取到的回調是:', response)
})

這個callHandler方法同樣會調用_doSend方法:將callback存儲到responseCallbacks中,key為callbakid;將消息存儲到sendMessageQueue中;messagingIframe執(zhí)行https://wvjb_queue_message

native的decidePolicyForNavigationAction方法監(jiān)聽到該消息后同樣通過WebViewJavascriptBridge._fetchQueue()去取消息。

根據(jù)callbackId創(chuàng)建一個responseCallback,根據(jù)message的handlerName從messageHandlers取出該回調,然后執(zhí)行:

WVJBResponseCallback responseCallback = NULL;
NSString* callbackId = message[@"callbackId"];
if (callbackId) {
    responseCallback = ^(id responseData) {
        if (responseData == nil) {
            responseData = [NSNull null];
        }
        WVJBMessage* msg = @{ @"responseId":callbackId, @"responseData":responseData };
        [self _queueMessage:msg];
    };
} else {
    responseCallback = ^(id ignoreResponseData) {
        // Do nothing
    };
}
WVJBHandler handler = self.messageHandlers[message[@"handlerName"]];
handler(message[@"data"], responseCallback);

調用完這個方法后,該消息已經(jīng)收到,然后將回調的內容回調給JS。 通過上面的代碼可以看到,回調JS的內容就是callbackId和responseData生成的message,調用_queueMessage方法。

_queueMessage方法上面已經(jīng)看過了,就是序列化消息、加入隊列、執(zhí)行WebViewJavascriptBridge._handleMessageFromObjC('%@');方法。

JS收到該消息后,處理返回的消息,從responseCallbacks中根據(jù)message中的responseId取出callback并且執(zhí)行。最后刪除responseCallbacks中的數(shù)據(jù),JS向native發(fā)送數(shù)據(jù)就完成了。

小結:

  • native側調用registerHandler方法注冊方法,方法名為JSTOOCCallback,將消息存儲到messageHandlers中,key為方法名,value為callback。
  • JS側調用callHandler方法:將responseCallback存儲到responseCallbacks中;將message存儲到sendMessageQueue中;messagingIframe執(zhí)行 http://wvjb_queue_message
  • native側監(jiān)聽到該消息后調用WebViewJavascriptBridge._fetchQueue()去取數(shù)據(jù)
  • 根據(jù)handlerName從messageHandlers中取出該callback;根據(jù)callbackId創(chuàng)建callback對象作為參數(shù)放到handlerName的方法中;執(zhí)行該回調。

總結

綜上,WebViewJavascriptBridge的核心流程就分析完了,最核心的點是JS通過加載iframe來通知native側;native側通過evaluateJavaScript方法去執(zhí)行JS。

從整個SDK來看,設計的非常好,值得借鑒學習:

  • 使用外觀模式統(tǒng)一調用接口,比如初始化WebViewJavascriptBridge的時候,不需要關心使用方使用的是UIWebView還是WKWebView,內部已經(jīng)處理好了。
  • 接口統(tǒng)一,不管是native側還是JS側,調用方法就是callHandler、注冊方法就是registerHandler,不需要關注內部實現(xiàn),使用非常方便。
  • 代碼簡潔,邏輯清晰,層次分明。從類的分布就能很清晰的看出各自的功能是什么。
  • 職責單一,比如decidePolicyForNavigationAction方法只負責監(jiān)聽事件、_fetchQueue是負責把消息轉換成JSON字符串返回、_doSend是發(fā)送消息到native、_dispatchMessageFromObjC是負責處理從OC返回的消息等。雖然decidePolicyForNavigationAction也能接收消息,但這樣就不會這么精簡了。
  • 擴展性好,目前decidePolicyForNavigationAction雖然只有初始化和發(fā)消息兩個事件,如果有其他事件還可以再擴展,這也得益于方法設計的職責單一,擴展對原有方法影響會很小。

以上就是iOS開發(fā)WebViewJavascriptBridge通訊原理解析的詳細內容,更多關于iOS WebViewJavascriptBridge通訊的資料請關注腳本之家其它相關文章!

相關文章

  • iOS App中UIPickerView選擇欄控件的使用實例解析

    iOS App中UIPickerView選擇欄控件的使用實例解析

    這篇文章主要介紹了iOS App中的UIPickerView選擇欄控件的使用,文中演示了兩個超詳細的例子,示例代碼為Objective-C,需要的朋友可以參考下
    2016-04-04
  • IOS使用TestFlight測試的使用方法

    IOS使用TestFlight測試的使用方法

    TestFlight是iOS系統(tǒng)上用來測試軟件的,打開了這個APP就相當于打開了新世界的大門,這個APP直接可以改變你對IOS系統(tǒng)封閉的看法,讓你擁有媲美安卓用戶的更多自主權!
    2022-12-12
  • IOS展開三級列表效果示例

    IOS展開三級列表效果示例

    今天介紹的是一個很不錯的三級列表展開效果的例子,文章運用實例代碼介紹的很詳細,提供給學習IOS的小伙伴們使用。
    2016-08-08
  • iOS中WKWebView白屏問題的分析與解決

    iOS中WKWebView白屏問題的分析與解決

    最近在工作中遇到了WKWebView白屏的問題,所以這篇文章主要給大家介紹了關于iOS中WKWebView白屏問題的分析與解決方法,文中通過示例代碼介紹的非常詳細,對同樣遇到這個問題的朋友具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧。
    2017-10-10
  • 淺析iOS給圖片加水印的方法

    淺析iOS給圖片加水印的方法

    在一些應用如微博中,為了防止用戶圖片被盜用,一般會在圖片上加上水印,接下來就給大家分享一個iOS中給圖片加水印的簡單方法.一起來看看吧。
    2016-08-08
  • iOS開發(fā)之銀行卡號識別

    iOS開發(fā)之銀行卡號識別

    本文給大家分享ios開發(fā)之銀行卡號識別功能,思路明確,需要的朋友參考下吧
    2016-12-12
  • Objective-C中關于實例所占內存的大小詳解

    Objective-C中關于實例所占內存的大小詳解

    這篇文章主要給大家介紹了關于Objective-C中實例所占內存的大小的相關資料,文中通過示例代碼介紹的非常詳細,對各位iOS開發(fā)者們具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-05-05
  • iOS把圖片緩存到本地的幾種方法(總結)

    iOS把圖片緩存到本地的幾種方法(總結)

    下面小編就為大家分享一篇iOS把圖片緩存到本地的幾種方法總結,具有很的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12
  • iOS在固定的label上動態(tài)顯示所有文字

    iOS在固定的label上動態(tài)顯示所有文字

    這篇文章給大家主要介紹了iOS中如何實現(xiàn),在固定的label上動態(tài)顯示所有文字的方法,文中給出了示例和思路,對大家的理解很有幫助,感興趣的朋友們下面來一起看看吧。
    2016-10-10
  • iOS內存管理Tagged Pointer使用原理詳解

    iOS內存管理Tagged Pointer使用原理詳解

    這篇文章主要為大家介紹了iOS內存管理Tagged Pointer使用原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-01-01

最新評論

石林| 依安县| 黄石市| 遵义县| 武功县| 甘德县| 自治县| 什邡市| 左云县| 越西县| 黄浦区| 芜湖县| 新晃| 高安市| 保山市| 容城县| 同江市| 鹤峰县| 中江县| 贵港市| 清镇市| 玛纳斯县| 博乐市| 武安市| 通化县| 乐清市| 临清市| 贵阳市| 盐津县| 曲靖市| 平顶山市| 施秉县| 双牌县| 高密市| 获嘉县| 通许县| 桐城市| 准格尔旗| 沈阳市| 昂仁县| 新余市|