91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

iOS開發之NSURLProtocol的示例分析

發布時間:2021-08-04 13:43:43 來源:億速云 閱讀:156 作者:小新 欄目:移動開發

這篇文章主要為大家展示了“iOS開發之NSURLProtocol的示例分析”,內容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領大家一起研究并學習一下“iOS開發之NSURLProtocol的示例分析”這篇文章吧。

NSURLProtocol

NSURLProtocol能夠讓你去重新定義蘋果的URL加載系統 (URL Loading System)的行為,URL Loading System里有許多類用于處理URL請求,比如NSURL,NSURLRequest,NSURLConnection和NSURLSession等,當URL Loading System使用NSURLRequest去獲取資源的時候,它會創建一個NSURLProtocol子類的實例,你不應該直接實例化一個NSURLProtocol,NSURLProtocol看起來像是一個協議,但其實這是一個類,而且必須使用該類的子類,并且需要被注冊。

使用場景

 不管你是通過UIWebView, NSURLConnection 或者第三方庫 (AFNetworking, MKNetworkKit等),他們都是基于NSURLConnection或者 NSURLSession實現的,因此你可以通過NSURLProtocol做自定義的操作。

  1. 重定向網絡請求

  2. 忽略網絡請求,使用本地緩存

  3. 自定義網絡請求的返回結果

  4. 一些全局的網絡請求設置

 接觸過iOS系統中URL Loading System都知道,NSURLProtocol是如此地強大,可以攔截應用內幾乎所有的網絡請求(除了WKWebView),并可以修改請求頭,返回client任意自定義的數據等等,據說很多做網絡緩存都是利用這個類的。

那么,首先講解一下NSURLProtocol怎么使用吧。

1. 定義一個NSURLProtocol的子類

在繼承NSURLProtocol中,我們需要實現

+ (BOOL)canInitWithRequest:(NSURLRequest *)request, 定義攔截請求的URL規則

- (void)startLoading, 對于攔截的請求,系統創建一個NSURLProtocol對象執行startLoading方法開始加載請求

- (void)stopLoading,對于攔截的請求,NSURLProtocol對象在停止加載時調用該方法

+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request,可選方法,對于需要修改請求頭的請求在該方法中修改

下面代碼定義了一個專門攔截https請求的NSURLProtocol子類,并通過CFHttpMessageRef重新請求

@interface CFHttpMessageURLProtocol () <NSStreamDelegate> { 
  NSMutableURLRequest *curRequest; 
  NSRunLoop *curRunLoop; 
  NSInputStream *inputStream; 
} 
 
@end 
 
@implementation CFHttpMessageURLProtocol 
 
/** 
 * 是否攔截處理指定的請求 
 * 
 * @param request 指定的請求 
 * 
 * @return 返回YES表示要攔截處理,返回NO表示不攔截處理 
 */ 
+ (BOOL)canInitWithRequest:(NSURLRequest *)request { 
   
  /* 防止無限循環,因為一個請求在被攔截處理過程中,也會發起一個請求,這樣又會走到這里,如果不進行處理,就會造成無限循環 */ 
  if ([NSURLProtocol propertyForKey:protocolKey inRequest:request]) { 
    return NO; 
  } 
   
  NSString *url = request.URL.absoluteString; 
   
  // 如果url以https開頭,則進行攔截處理,否則不處理 
  if ([url hasPrefix:@"https"]) { 
    return YES; 
  } 
  return NO; 
} 
 
/** 
 * 如果需要對請求進行重定向,添加指定頭部等操作,可以在該方法中進行 
 */ 
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request { 
  return request; 
} 
 
/** 
 * 開始加載,在該方法中,加載一個請求 
 */ 
- (void)startLoading { 
  NSMutableURLRequest *request = [self.request mutableCopy]; 
  // 表示該請求已經被處理,防止無限循環 
  [NSURLProtocol setProperty:@(YES) forKey:protocolKey inRequest:request]; 
  curRequest = request; 
  [self startRequest]; 
} 
 
/** 
 * 取消請求 
 */ 
- (void)stopLoading { 
  if (inputStream.streamStatus == NSStreamStatusOpen) { 
    [inputStream removeFromRunLoop:curRunLoop forMode:NSRunLoopCommonModes]; 
    [inputStream setDelegate:nil]; 
    [inputStream close]; 
  } 
  [self.client URLProtocol:self didFailWithError:[[NSError alloc] initWithDomain:@"stop loading" code:-1 userInfo:nil]]; 
}

以上代碼中的startRequest方法是通過復制原始請求頭,使用CFHttpMessageRef重新發起請求的,關于這部分的代碼由于跟本文章內容關系不大,這里就先不放,有興趣的朋友可以參考我的下一篇博客。

2. 在網絡請求前注冊NSURLProtocol

 // 注冊攔截請求的NSURLProtocol 
[NSURLProtocol registerClass:[CFHttpMessageURLProtocol class]];

對于NSURLSession的請求,注冊NSURLProtocol的方式稍有不同,是通過NSURLSessionConfiguration注冊的

// NSURLSession例子 
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 
NSArray *protocolArray = @[ [CFHttpMessageURLProtocol class] ]; 
configuration.protocolClasses = protocolArray; 
NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]]; 
NSURLSessionTask *task = [session dataTaskWithRequest:_request]; 
[task resume];

3. 請求結束后注銷NSURLProtocol

[NSURLProtocol unregisterClass:[CFHttpMessageURLProtocol class]];

好了,到這里NSURLProtocol的使用方法大家應該有所了解了。下面主要講一下NSURLProtocol在使用過程中可能會遇到的坑,給自己以及需要的朋友留個提醒。

1. 上面一開始就已經說了,對于WebView的請求,目前NSURLProtocol還不能攔截WKWebView的請求,只能攔截UIWebview的,但后者好像AppStore已經不讓審核通過了(尷尬臉)。

2. NSURLProtocol在攔截NSURLSession的POST請求時不能獲取到Request中的HTTPBody,這個貌似早就國外的論壇上傳開了,但國內好像還鮮有人知,據蘋果官方的解釋是Body是NSData類型,即可能為二進制內容,而且還沒有大小限制,所以可能會很大,為了性能考慮,索性就攔截時就不拷貝了(內流滿面臉)。為了解決這個問題,我們可以通過把Body數據放到Header中,不過Header的大小好像是有限制的,我試過2M是沒有問題,不過超過10M就直接Request timeout了。。。而且當Body數據為二進制數據時這招也沒轍了,因為Header里都是文本數據,另一種方案就是用一個NSDictionary或NSCache保存沒有請求的Body數據,用URL為key,最后方法就是別用NSURLSession,老老實實用古老的NSURLConnection算了。。。

3. 使用NSURLProtocol時,在那兩個類方法可以發送同步網絡請求,而實例方法,如startLoading則進入死鎖,直至超時,原因是執行實例方法所在的線程并沒有啟動runloop,而NSURLConnection這些網絡請求需要依賴于runloop的,因此這些請求根本發不出去,所以必須使用異步請求,NSURLConnection/NSURLSession的異步請求的線程保證啟動了runloop。

以上是“iOS開發之NSURLProtocol的示例分析”這篇文章的所有內容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內容對大家有所幫助,如果還想學習更多知識,歡迎關注億速云行業資訊頻道!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

博罗县| 镇沅| 绥江县| 韩城市| 盈江县| 灵武市| 临沂市| 沽源县| 河间市| 贺州市| 长泰县| 运城市| 肃北| 青田县| 佛坪县| 获嘉县| 南开区| 奉化市| 堆龙德庆县| 抚顺市| 弋阳县| 万盛区| 钟山县| 裕民县| 娄烦县| 开原市| 清苑县| 平定县| 天水市| 台北县| 盈江县| 黄平县| 登封市| 张家口市| 和政县| 宣汉县| 菏泽市| 桦甸市| 噶尔县| 莆田市| 遵化市|