ASIHttpRequest是一个非常好的库,只是直接使用稍嫌麻烦,以下就尝试来封装一下吧。
思路:每次请求时,须要创建一个ASIHttpRequest对象,设置它的属性(url,delegate。postValue,requestMethod等)之后就可以開始异步请求。所以我们能够创建一个类。对外提供一个请求方法,结构例如以下:
@interface RequestService : NSObject
+ (void)requestWithUrlString:(NSString *)urlString
params:(NSDictionary *)params
httpMethod:(NSString *)httpMethod
delegate:(id)delegate;
@end
使用例如以下:
[RequestService requestWithUrlString:urlString
params:params
httpMethod:httpMethod
delegate:delegate];
看起来非常easy嘛,这样即可了吗?
考虑一个问题,此时传入的delegate是请发起请求的对象。假设我们想要对请求返回做统一的处理,就无法做到了。为了实现这一目的,能够将ASIHttpRequest的delegate设置成RequestService实例对象,请求返回昨晚处理后再将处理结果通知给发起请求的对象。
那么RequestService请求的方法就须要改成实例方法。
改动后代码例如以下:
@protocol RequestServiceDelegate <NSObject>
- (void)requestWillBegin;
- (void)requestDidSucceedWithData:(id)data;
- (void)requestDidFailWithError:(NSError *)error;
@end
@interface RequestService : NSObject
@property (nonatomic,assign)id<RequestServiceDelegate> delegate;
- (void)requestWithUrlString:(NSString *)urlString
params:(NSDictionary *)params
httpMethod:(NSString *)httpMethod;
@end注意除了将类方法改动成实例方法之外,我们去掉了方法传參ASIHttpRequestDelegate,同一时候给它加了自己的delegate属性。用于在请求返回处理完毕后通知发起请求的对象。
使用例如以下:
RequestService *request = [[RequestService alloc] init];
request.delegate = self;
[request requestWithUrlString:urlString
params:params
httpMethod:httpMethod];
在这里须要特别注意创建的request对象的生命周期,由于ASIHttpRequest运行的是异步请求,当请求完毕,通知request对象时。假设request对象已经销毁,那么代码就会报错。因此使用时,须要发起请求的对象持有此request。并在请求完毕后释放它。
让每一个对象管理请求,听起来就非常麻烦,又违背了想要统一管理的初衷,那么应该怎么办呢?
让我们来使用单例吧!
创建一个单例对象HttpClient。它有一个属性requestItems。
每次发起请求时,将请求的Item存入该属性。
请求结束后移除Item。
对外,它要提供一个request方法,并须要一个属性保存发起请求的对象。
HttpClient的结构例如以下:
@protocol HttpClientDelegate <NSObject>
- (void)requestDidFinishWithData:(NSDictionary *)data urlString:(NSString *)urlString nTag:(NSInteger)nTag sKey:(NSString *)sKey;
- (void)requestDidFailWithError:(NSError *)error urlString:(NSString *)urlString nTag:(NSInteger)nTag sKey:(NSString *)sKey;
@end
@interface HttpClient : NSObject
@property (nonatomic,strong)NSMutableDictionary *items;
+ (HttpClient *)sharedClient;
- (void)requestWithUrl:(NSString *)urlString
params:(NSDictionary *)params
httpMethod:(NSString *)httpMethod
delegate:(id<HttpClientDelegate>)delegate;
@end使用例如以下:[[HttpClient sharedClient] requestWithUrl:kProductListURL
params:params
httpMethod:@"GET"
delegate:self];HttpClient内部怎样实现对每次request的管理呢?首先在请求时,创建一个requestItem,调用requestItem的请求方法,然后将其增加requestItems。当requestItem接收到返回时,通知HttpClient,最后由HttpClient通知发起请求的对象,并移除该requestItem。
HttpClient的request方法例如以下:
- (void)requestWithUrl:(NSString *)urlString
params:(NSDictionary *)params
httpMethod:(NSString *)httpMethod
delegate:(id<HttpClientDelegate>)delegate
{
HttpRequestItem *item = [[HttpRequestItem alloc] init];
item.delegate = delegate;
[item requestWithUrlString:urlString params:params httpMethod:httpMethod];
NSUInteger hashValue = [item hash];
[self.items addObject:item];
}用于接收RequestItem的通知方法例如以下:- (void)didFinishWithItem:(HttpRequestItem *)item
error:(NSError *)error
{
if (error == nil) {
// 请求成功
if (item.delegate && [item.delegate respondsToSelector:@selector(requestDidFinishWithData:urlString:nTag:sKey:)]) {
NSDictionary *data = [NSJSONSerialization JSONObjectWithData:item.httpReq.responseData options:NSJSONReadingMutableContainers error:nil];
[item.delegate requestDidFinishWithData:data urlString:item.urlString nTag:item.nTag sKey:item.sKey];
}
} else {
// 请求出错
if (item.delegate && [item.delegate respondsToSelector:@selector(requestDidFailWithError:urlString:nTag:sKey:)]) {
[item.delegate requestDidFailWithError:error urlString:item.urlString nTag:item.nTag sKey:item.sKey];
}
}
[self removeItem:item];
}HttpRequestItem也就是我们之前的RequestService,它接收ASIHttpRequest的返回的方法例如以下:#pragma mark - ASIHTTPRequest delegate
- (void)requestFinished:(ASIHTTPRequest *)request
{
NSError *error = nil;
// doSomething with response here....
if ([[HttpClient sharedClient] respondsToSelector:@selector(didFinishWithItem:error:)]) {
[[HttpClient sharedClient] performSelector:@selector(didFinishWithItem:error:) withObject:self withObject:error];
}
}
- (void)requestFailed:(ASIHTTPRequest *)request
{
if ([[HttpClient sharedClient] respondsToSelector:@selector(didFinishWithItem:error:)]) {
[[HttpClient sharedClient] performSelector:@selector(didFinishWithItem:error:) withObject:self withObject:request.error];
}
}以上,主要的雏形已经出来了~还有哪些能够改进的地方呢?
考虑两个问题:
1.同一个对象,可能会发起多次请求,怎样差别这些请求的返回?
2.假设想主动取消某个正在进行的请求,应该怎么办?
对于问题1,可在请求时传入參数,如tag、key等,由RequestItem保存这些參数,请求完毕后依据这些參数来区分不同的请求。
对于问题2。相应方法是记录每一个RequestItem的HashValue,并对外提供依据HashValue取消相应请求的方法。
完整的代码例如以下:
HttpClient.h
#import <Foundation/Foundation.h>
@protocol HttpClientDelegate <NSObject>
- (void)requestDidFinishWithData:(NSDictionary *)data urlString:(NSString *)urlString nTag:(NSInteger)nTag sKey:(NSString *)sKey;
- (void)requestDidFailWithError:(NSError *)error urlString:(NSString *)urlString nTag:(NSInteger)nTag sKey:(NSString *)sKey;
@end
@interface HttpClient : NSObject
@property (nonatomic,strong)NSMutableDictionary *items;
+ (HttpClient *)sharedClient;
- (NSUInteger)requestWithUrl:(NSString *)urlString
params:(NSDictionary *)params
httpMethod:(NSString *)httpMethod
delegate:(id<HttpClientDelegate>)delegate;
- (NSUInteger)requestWithUrl:(NSString *)urlString
params:(NSDictionary *)params
httpMethod:(NSString *)httpMethod
delegate:(id<HttpClientDelegate>)delegate
nTag:(NSInteger)nTag;
- (NSUInteger)requestWithUrl:(NSString *)urlString
params:(NSDictionary *)params
httpMethod:(NSString *)httpMethod
delegate:(id<HttpClientDelegate>)delegate
sKey:(NSString *)sKey;
- (NSUInteger)requestWithUrl:(NSString *)urlString
params:(NSDictionary *)params
httpMethod:(NSString *)httpMethod
delegate:(id<HttpClientDelegate>)delegate
nTag:(NSInteger)nTag
sKey:(NSString *)sKey;
// 取消请求
- (BOOL)cancelRequestWithHashValue:(NSUInteger)hashValue;
@endHttpClient.m
HttpRequestItem.h#import <Foundation/Foundation.h> #import "ASIFormDataRequest.h" #import "RequestConstants.h" #import "HttpClient.h" @interface HttpRequestItem : NSObject @property (nonatomic,strong)ASIHTTPRequest *httpReq; @property (nonatomic,copy)NSString *urlString; @property (nonatomic,assign)NSInteger nTag; @property (nonatomic,copy)NSString *sKey; @property (nonatomic,assign)id<HttpClientDelegate> delegate; - (void)requestWithUrlString:(NSString *)urlString params:(NSDictionary *)params httpMethod:(NSString *)httpMethod; @endHttpRequestItem.m