IOS開源網(wǎng)絡(luò)庫AFNetworking已經(jīng)成為了IOS程序開發(fā)的首選官还、亦可以說是必備堕虹,無數(shù)IOS
的“先哲”們撰文稱贊此庫良好的設(shè)計(jì)和功能的強(qiáng)大鬼雀,以致后來的開發(fā)者在項(xiàng)目中都不會去
考慮其它的網(wǎng)絡(luò)庫实撒,而直接選擇AFNetworking靴患。這里就來總結(jié)一下使用它的一般程式桨菜,在
總結(jié)過程中學(xué)習(xí)和成長豁状。
HttpClient
我們在使用AFHTTPSessionManager的時候,一般均會對其進(jìn)行封裝倒得,以滿足App的各種要求泻红。
所以這里選擇對其進(jìn)行擴(kuò)展,設(shè)計(jì)如下:
@interface LNHttpClient : AFHTTPSessionManager
+ (instancetype)sharedClient;
+ (void)setTimeout:(NSTimeInterval)timeout;
+ (void)setResponseType:(LNHttpResponseType)type;
- (void)setHttpHeader;
@end
該繼承類的實(shí)現(xiàn)需要注意如下幾點(diǎn):
- 繼承AFHTTPSessionManager免不了對initWithBaseURL的覆寫霞掺,并在其中注冊一些通知谊路,用于
檢測用戶的登陸和登出,以便Client做相應(yīng)的處理菩彬。 - setHttpHeader可以設(shè)置Http頭部缠劝,比如token潮梯、userId等等。
- 中間兩個方法使得開發(fā)者可以控制每一次請求的timeout和responseType惨恭。
APIService
APIService是所有網(wǎng)絡(luò)請求的入口酷麦,所有Service的網(wǎng)絡(luò)調(diào)用均使用該類來完成,我們項(xiàng)目中
使用proto-buf來作為數(shù)據(jù)交換的類型喉恋,其設(shè)計(jì)力求簡介:
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;
該類的設(shè)計(jì)是對于AFHTTPSessionManager的封裝沃饶,是所有Service類的基類。實(shí)現(xiàn)要點(diǎn):
- 定義了兩個block轻黑,分別用來處理成功和失敗的調(diào)用糊肤。
- modelClass用來解析ContentType的數(shù)據(jù),此處是proto-buf氓鄙。
- 此類派生的各個Service來處理不同的業(yè)務(wù)場景馆揉。
AFHTTPRequestSerializer覆寫
在客戶端發(fā)送請求時,我們有時需要設(shè)置request的content-Type抖拦,以便于服務(wù)端能夠根據(jù)
content-Type來處理不同格式的數(shù)據(jù)升酣,比如AFNetworking中自帶的AFJSONRequestSerializer,
就能夠把請求的數(shù)據(jù)轉(zhuǎn)化為JSON格式,并且把content-Type設(shè)置為application/json态罪。這里
我們的請求數(shù)據(jù)格式為proto-buf噩茄,而AF庫并沒有給我們提供相關(guān)的默認(rèn)實(shí)現(xiàn),這時候就需要
我們自己來實(shí)現(xiàn)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的主要覆寫方法绩聘。同理我們只需要仿照這個例子來
實(shí)現(xiàn)AFProtoRequestSerializer即可。
URL緩存
說起HTTP請求耗啦,就不得不聊到緩存凿菩,每次去請求相同的URL的數(shù)據(jù)顯然是不劃算的,所以將
每次URL請求的數(shù)據(jù)緩存起來帜讲,以后當(dāng)有相同的URL請求時衅谷,直接使用緩存數(shù)據(jù)即可。使用
緩存一般有兩種選擇似将。
-
NSURLCache
系統(tǒng)提供的默認(rèn)緩存获黔,使用該方式可以減少開發(fā)的難度,但是在使用過程中需要注意的
是- 該緩存只能用在GET請求上玩郊,并不支持Post肢执。
- 緩存方式盡量選擇NSURLRequestReturnCacheDataDontLoad,如果有緩存直接返回?cái)?shù)據(jù)
如果沒有緩存則不發(fā)送請求译红,返回nil预茄,我們手工來再發(fā)一次請求。這樣做可以規(guī)避一
些蘋果實(shí)現(xiàn)緩存的坑。
-
**URLCache
自己實(shí)現(xiàn)的緩存耻陕,我們只需要擴(kuò)展NSURLCache即可拙徽,使用擴(kuò)展的cache來代替原生的實(shí)例。
這樣我們就可以人為控制緩存的URL范圍和數(shù)據(jù)存儲了诗宣,簡單實(shí)現(xiàn)如下:@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
##總結(jié)
通過以上講解膘怕,相信你可以從容地處理好網(wǎng)絡(luò)請求模塊的設(shè)計(jì)。