IOS開源網絡庫AFNetworking已經成為了IOS程序開發的首選、亦可以說是必備,無數IOS
的“先哲”們撰文稱贊此庫良好的設計和功能的強大,以致后來的開發者在項目中都不會去
考慮其它的網絡庫,而直接選擇AFNetworking。這里就來總結一下使用它的一般程式,在
總結過程中學習和成長。
HttpClient
我們在使用AFHTTPSessionManager的時候,一般均會對其進行封裝,以滿足App的各種要求。
所以這里選擇對其進行擴展,設計如下:
@interface LNHttpClient : AFHTTPSessionManager
+ (instancetype)sharedClient;
+ (void)setTimeout:(NSTimeInterval)timeout;
+ (void)setResponseType:(LNHttpResponseType)type;
- (void)setHttpHeader;
@end
該繼承類的實現需要注意如下幾點:
- 繼承AFHTTPSessionManager免不了對initWithBaseURL的覆寫,并在其中注冊一些通知,用于
檢測用戶的登陸和登出,以便Client做相應的處理。 - setHttpHeader可以設置Http頭部,比如token、userId等等。
- 中間兩個方法使得開發者可以控制每一次請求的timeout和responseType。
APIService
APIService是所有網絡請求的入口,所有Service的網絡調用均使用該類來完成,我們項目中
使用proto-buf來作為數據交換的類型,其設計力求簡介:
typedef void (^APISuccessHandler)(id responseObject);
typedef void (^APIFailureHandler)(NSInteger code, NSString *msg);
@interface APIService : NSObject
+ (NSURLSessionTask *)POST:(NSString *)relativePath
protobuf:(NSData *)proto
modelClass:(Class)modelClass
success:(APISuccessHandler)success
failure:(APIFailureHandler)failure;
+ (NSURLSessionTask *)GET:(NSString *)relativePath
protobuf:(NSData *)proto
modelClass:(Class)modelClass
success:(APISuccessHandler)success
failure:(APIFailureHandler)failure;
該類的設計是對于AFHTTPSessionManager的封裝,是所有Service類的基類。實現要點:
- 定義了兩個block,分別用來處理成功和失敗的調用。
- modelClass用來解析ContentType的數據,此處是proto-buf。
- 此類派生的各個Service來處理不同的業務場景。
AFHTTPRequestSerializer覆寫
在客戶端發送請求時,我們有時需要設置request的content-Type,以便于服務端能夠根據
content-Type來處理不同格式的數據,比如AFNetworking中自帶的AFJSONRequestSerializer,
就能夠把請求的數據轉化為JSON格式,并且把content-Type設置為application/json。這里
我們的請求數據格式為proto-buf,而AF庫并沒有給我們提供相關的默認實現,這時候就需要
我們自己來實現AFProtoRequestSerializer。
- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
withParameters:(id)parameters
error:(NSError *__autoreleasing *)error
{
NSParameterAssert(request);
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
return [super requestBySerializingRequest:request withParameters:parameters error:error];
}
NSMutableURLRequest *mutableRequest = [request mutableCopy];
[self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) {
if (![request valueForHTTPHeaderField:field]) {
[mutableRequest setValue:value forHTTPHeaderField:field];
}
}];
if (parameters) {
if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
[mutableRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
}
[mutableRequest setHTTPBody:[NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error]];
}
return mutableRequest;
}
上面的代碼是AFJSONRequestSerializer的主要覆寫方法。同理我們只需要仿照這個例子來
實現AFProtoRequestSerializer即可。
URL緩存
說起HTTP請求,就不得不聊到緩存,每次去請求相同的URL的數據顯然是不劃算的,所以將
每次URL請求的數據緩存起來,以后當有相同的URL請求時,直接使用緩存數據即可。使用
緩存一般有兩種選擇。
-
NSURLCache
系統提供的默認緩存,使用該方式可以減少開發的難度,但是在使用過程中需要注意的
是- 該緩存只能用在GET請求上,并不支持Post。
- 緩存方式盡量選擇NSURLRequestReturnCacheDataDontLoad,如果有緩存直接返回數據
如果沒有緩存則不發送請求,返回nil,我們手工來再發一次請求。這樣做可以規避一
些蘋果實現緩存的坑。
-
**URLCache
自己實現的緩存,我們只需要擴展NSURLCache即可,使用擴展的cache來代替原生的實例。
這樣我們就可以人為控制緩存的URL范圍和數據存儲了,簡單實現如下:@implementation LNURLCache - (void)storeCachedResponse:(NSCachedURLResponse *)cachedResponse forRequest:(NSURLRequest *)request { if ([self shouldManuallyCacheRequest:request]) { [[LNCache globalCache] setObject:cachedResponse forKey:request.URL.absoluteString withTimeoutInterval:kTimeOneYear]; } else { [super storeCachedResponse:cachedResponse forRequest:request]; } } - (NSCachedURLResponse *)cachedResponseForRequest:(NSURLRequest *)request { if ([self shouldManuallyCacheRequest:request]) { return (NSCachedURLResponse *)[[LNCache globalCache] objectForKey:request.URL.absoluteString]; } else { return [super cachedResponseForRequest:request]; } } - (BOOL)shouldManuallyCacheRequest:(NSURLRequest *)request { return [request.URL.host hasSuffix:kCDNHostName]; } @end
##總結
通過以上講解,相信你可以從容地處理好網絡請求模塊的設計。