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;

@end
HttpClient.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;

@end

HttpRequestItem.m





相关文章: