zoukankan      html  css  js  c++  java
  • ASIHttpRequest封装

    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
    #import "HttpClient.h"
    #import "HttpRequestItem.h"
    
    @implementation HttpClient
    
    + (HttpClient *)sharedClient {
        static HttpClient *_sharedClient = nil;
        static dispatch_once_t oncePredicate;
        dispatch_once(&oncePredicate, ^{
            _sharedClient = [[self alloc] init];
            _sharedClient.items = [NSMutableDictionary dictionary];
        });
        
        return _sharedClient;
    }
    
    - (NSUInteger)requestWithUrl:(NSString *)urlString
                          params:(NSDictionary *)params
                      httpMethod:(NSString *)httpMethod
                        delegate:(id<HttpClientDelegate>)delegate
    {
        return [self requestWithUrl:urlString params:params httpMethod:httpMethod delegate:delegate nTag:0 sKey:nil];
    }
    
    - (NSUInteger)requestWithUrl:(NSString *)urlString
                          params:(NSDictionary *)params
                      httpMethod:(NSString *)httpMethod
                        delegate:(id<HttpClientDelegate>)delegate
                            nTag:(NSInteger)nTag
    {
        return [self requestWithUrl:urlString params:params httpMethod:httpMethod delegate:delegate nTag:nTag sKey:nil];
    }
    
    - (NSUInteger)requestWithUrl:(NSString *)urlString
                          params:(NSDictionary *)params
                      httpMethod:(NSString *)httpMethod
                        delegate:(id<HttpClientDelegate>)delegate
                            sKey:(NSString *)sKey
    {
        return [self requestWithUrl:urlString params:params httpMethod:httpMethod delegate:delegate nTag:0 sKey:sKey];
    }
    
    - (NSUInteger)requestWithUrl:(NSString *)urlString
                          params:(NSDictionary *)params
                      httpMethod:(NSString *)httpMethod
                        delegate:(id<HttpClientDelegate>)delegate
                            nTag:(NSInteger)nTag
                            sKey:(NSString *)sKey
    {
        HttpRequestItem *item = [[HttpRequestItem alloc] init];
        item.delegate = delegate;
        item.nTag = nTag;
        item.sKey = sKey;
        [item requestWithUrlString:urlString params:params httpMethod:httpMethod];
        
        NSUInteger hashValue = [item hash];
        [self.items setObject:item forKey:@(hashValue)];
        return hashValue;
    }
    
    - (BOOL)cancelRequestWithHashValue:(NSUInteger)hashValue
    {
        HttpRequestItem *item = [_items objectForKey:@(hashValue)];
        if (item) {
            [item.httpReq clearDelegatesAndCancel];
            [_items removeObjectForKey:@(hashValue)];
        }
        
        return YES;
    }
    
    #pragma mark - actions
    - (void)removeItem:(HttpRequestItem *)item
    {
        NSUInteger hashValue = [item hash];
        id object = [_items objectForKey:@(hashValue)];
        if (object != nil) {
            [[(HttpRequestItem *)object httpReq] clearDelegatesAndCancel];
            [_items removeObjectForKey:@(hashValue)];
        }
    }
    
    #pragma mark - HttpRequestItem delegate
    // 请求结束
    - (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];
    }
    
    @end

    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

    #import "HttpRequestItem.h"
    
    NSString * const kHttpBaseURLString = @"http://192.168.33.6:8080/";
    
    @implementation HttpRequestItem
    
    - (void)requestWithUrlString:(NSString *)urlString
                          params:(NSDictionary *)params
                      httpMethod:(NSString *)httpMethod
    {
        ASIFormDataRequest *request;
        NSURL *url;
        urlString = [kHttpBaseURLString stringByAppendingString:urlString];
        
        if ([[httpMethod lowercaseString] isEqualToString:@"post"]) {
            // post方式訪问接口
            url = [NSURL URLWithString:urlString];
            request = [ASIFormDataRequest requestWithURL:url];
            [request setRequestMethod:@"POST"];
            
            for (NSString *key in params) {
                id value = [params objectForKey:key];
                if (![value isKindOfClass:[NSData class]]) {
                    [request addPostValue:value forKey:key];
                } else {
                    [request addData:value forKey:key];
                }
            }
        } else {
            // get方式訪问接口
            urlString = [urlString stringByAppendingString:@"?format=json"];
            for (NSString *key in params) {
                urlString = [urlString stringByAppendingFormat:@"&%@=%@", key, [params objectForKey:key]];
            }
            
            NSLog(@"-----------url:%@-----------",urlString);
            
            NSURL *url = [NSURL URLWithString:urlString];
            
            request = [ASIFormDataRequest requestWithURL:url];
            //设置缓存方式
            //[request setSecondsToCache:60*60*24*30];
            //[request setDownloadCache:[DFAppDelegate myCache]];
            //设置缓存数据存储策略。这里採取的是假设无更新或无法联网就读取缓存数据
            [request setCachePolicy:ASIAskServerIfModifiedCachePolicy|ASIFallbackToCacheIfLoadFailsCachePolicy];
            [request setCacheStoragePolicy:ASICachePermanentlyCacheStoragePolicy];
            
            [request setRequestMethod:@"GET"];
        }
        
        request.delegate = self;
        request.timeOutSeconds = 60;
        [request startAsynchronous];
        
        self.httpReq = request;
        self.urlString = urlString;
    }
    
    #pragma mark - ASIHTTPRequest delegate
    - (void)requestFinished:(ASIHTTPRequest *)request
    {
        NSError *error = nil;
        if (request.responseStatusCode == 500) {
            // server状态500
            error = [NSError errorWithDomain:@"server出错" code:-10000 userInfo:nil];
        }
    
        id result = [NSJSONSerialization JSONObjectWithData:request.responseData options:NSJSONReadingMutableContainers error:nil];
        if ([result isKindOfClass:[NSDictionary class]]) {
            NSString *status = [result objectForKey:@"status"];
            
            if (![status isEqualToString:@"success"]) {
                // 请求返回errorCode
                error = [NSError errorWithDomain:[result objectForKey:@"info"] code:-9998 userInfo:nil];
            }
        } else {
            error = [NSError errorWithDomain:@"server返回值出错" code:-9999 userInfo:nil];
        }
    
        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];
        }
    }
    
    @end




  • 相关阅读:
    POJ 3263 Tallest Cow(线段树)
    面试题54——表示数值的字符串
    ORA-01555错误总结(二)
    《AndroidStudio每日一贴》11. 重构之提炼为常量
    机器学习系统构建
    jsp不通过form和Ajax提交
    南邮算法分析与设计实验2 动态规划法
    cocos2d-x 3.2 之 2048 —— 第五篇
    Cocos2d-x学习资源集锦+有奖抽楼活动
    VMware虚拟机无法识别U盘解决方式
  • 原文地址:https://www.cnblogs.com/blfbuaa/p/6708074.html
Copyright © 2011-2022 走看看