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];

看起来很简单嘛,这样就行了吗?

考虑一个问题,此时传入的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) {
        // 服务器状态500
        error = [NSError errorWithDomain:@"服务器出错" 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:@"服务器返回值出错" 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
时间: 2024-10-05 12:34:31

ASIHttpRequest封装的相关文章

对ASIHTTPRequest的封装

.h文件 // // HttpUtil.h // SmallTaurus // // Created by Fuer on 14-7-7. // Copyright (c) 2014年 FuEr. All rights reserved. // /** * 对ASI的封装 */ #import <Foundation/Foundation.h> #import "ASIHTTPRequest.h" #import "ASIFormDataRequest.h&quo

用Block封装ASIHttpRequest

用Block封装ASIHttpRequest 横方便的网络请求方法,不用每次都写代理方法.使代码先得很整齐,不会凌乱. 接口部分: // // LYHASIRequestBlock.h // ASIBlockTest // // Created by Charles Leo on 14-7-23. // Copyright (c) 2014年 Charles Leo. All rights reserved. // #import <Foundation/Foundation.h> #impo

iOS疯狂详解之ASIHttpRequest的简单封装

//  iOS疯狂详解之ASIHttpRequest的简单封装 //  WLHTTPClient.h //  WLWLListen // //  Created by long on 14-12-15. //  Copyright (c) 2014年 WLong. All rights reserved. // #import <Foundation/Foundation.h> #import "ASIFormDataRequest.h" @protocol WLHTTPC

AFNetworking 和 ASIHTTPRequest

在开发iOS应用过程中,如何高效的与服务端API进行数据交换,是一个常见问题.一般开发者都会选择一个第三方的网络组件作为服务,以提高开发效率和稳定性.这些组件把复杂的网络底层操作封装成友好的类和方法,并且加入异常处理等. 那么,大家最常用的组件是什么?这些组件是如何提升开发效率和稳定性的?哪一款组件适合自己,是 AFNetworking(AFN)还是 ASIHTTPRequest(ASI)?几乎每一个iOS互联网应用开发者都会面对这样的选择题,要从这两个最常用的组件里选出一个好的还真不是那么容易

ASIHTTPRequest类库简介和使用说明

官方网站: http://allseeing-i.com/ASIHTTPRequest/ .可以从上面下载到最新源码,以及获取到相关的资料. 使用iOS SDK中的HTTP网络请求API,相当的复杂,调用很繁琐,ASIHTTPRequest就是一个对CFNetwork API进行了封装,并且使用起来非常简单的一套API,用Objective-C编写,可以很好的应用在Mac OS X系统和iOS平台的应用程序中.ASIHTTPRequest适用于基本的HTTP请求,和基于REST的服务之间的交互.

iOS网络层框架之AFNetworking与 ASIHTTPRequest对比

在开发iOS应用过程中,如何高效的与服务端API进行数据交换,是一个常见问题.一般开发者都会选择一个第三方的网络组件作为服务,以提高开发效率和稳定性.这些组件把复杂的网络底层操作封装成友好的类和方法,并且加入异常处理等. 那么,大家最常用的组件是什么?这些组件是如何提升开发效率和稳定性的?哪一款组件适合自己,是 AFNetworking(AFN)还是 ASIHTTPRequest(ASI)?几乎每一个iOS互联网应用开发者都会面对这样的选择题,要从这两个最常用的组件里选出一个好的还真不是那么容易

iOS ASIHTTPRequest详解

ASIHTTPRequest对CFNetwork API进行了封装,并且使用起来非常简单,用Objective-C编写,可以很好的应用在Mac OS X系统和iOS平台的应用程序中.ASIHTTPRequest适用于基本的HTTP请求,和基于REST的服务之间的交互. ASIHTTPRequest功能很强大,主要特色如下: l 通过简单的接口,即可完成向服务端提交数据和从服务端获取数据的工作 l 下载的数据,可存储到内存中或直接存储到磁盘中 l 能上传本地文件到服务端 l 可以方便的访问和操作请

网络请求封装

网络请求封装 // // ASIHTTPRequest+Request.h // CloudShopping // // Created by sixiaobo on 14-7-9. // Copyright (c) 2014年 com.Uni2uni. All rights reserved. // #import "ASIFormDataRequest.h" #import "ASIDownloadCache.h" // downloadData是返回的数据,如

ASIHTTPRequest的环境配置和使用示例

ASIHTTPRequest类库是基于ISO SDK的一组网络请求的API.IOS SDK的网络组件CFNetwork API操作起来非常复杂.而ASIHTTPRequest类库是对CFNetwork API的封装,提供了基于HTTP请求的各类操作接口. 比如:下载上传数据,获得HTTP头信息,支持cookie,支持缓存/压缩,端点续传等. 在这里特酷吧整理了ASIHTTPRequest环境的配置方法. 特酷吧采用的是xcode 4.2,到官方网站http://allseeing-i.com/A