现在的位置: 首页 > 综合 > 正文

ASIHTTPRequest足够了吗?

2012年11月21日 ⁄ 综合 ⁄ 共 9370字 ⁄ 字号 评论关闭

        大家都知道ASIHTTPRequest系列的类很好用,功能很强大。但也像NSURLConnection一样,一个网络请求就需要实例化一个对象,而且无法避免重复请求的问题。

        我个人不习惯用ASIHTTPRequest,因为它功能太强大了,函数太多了,而我们平时的项目仅仅是处理基于HTTP协议的网络交互,用ASIHTTPRequest未免太“奢侈”了。更重要的是,它并无法避免网络的重复请求的问题,而且无法控制网络请求数量,所以仅仅使用ASIHTTPRequest还不够。

        事实上,用NSURLConnection足够了。下面是我写的封装


HTTPConnection.h

//
//  HTTPConnection.h
//  
//
//  Created by Jianhong Yang on 12-1-3.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#import <Foundation/Foundation.h>


@protocol HTTPConnectionDelegate;

@interface HTTPConnection : NSObject {
@private
    //
    int _numberOfURLConnection;
    int _maxNumberOfURLConnection;
    NSMutableArray *_marrayTaskDic;
    
    id <HTTPConnectionDelegate> _delegate;
}

@property (nonatomic, assign) int maxNumberOfURLConnection;
@property (nonatomic, assign) id <HTTPConnectionDelegate> delegate;

// 根据URL获取Web数据
- (BOOL)requestWebDataWithURL:(NSString *)strURL andParam:(NSDictionary *)dicParam priority:(BOOL)priority;

// 根据URLRequest获取Web数据
- (BOOL)requestWebDataWithRequest:(NSURLRequest *)request andParam:(NSDictionary *)dicParam priority:(BOOL)priority;

//取消网络请求
- (BOOL)cancelRequest:(NSDictionary *)dicParam;

//清空网络请求
- (void)clearRequest;

@end


@protocol HTTPConnectionDelegate <NSObject>

@optional

// 网络数据下载失败
- (void)httpConnect:(HTTPConnection *)httpConnect error:(NSError *)error with:(NSDictionary *)dicParam;

// 服务器返回的HTTP信息头
- (void)httpConnect:(HTTPConnection *)httpConnect receiveResponseWithStatusCode:(NSInteger)statusCode 
 andAllHeaderFields:(NSDictionary *)dicAllHeaderFields with:(NSDictionary *)dicParam;

// 服务器返回的部分数据
- (void)httpConnect:(HTTPConnection *)httpConnect receiveData:(NSData *)data with:(NSDictionary *)dicParam;

// 网络数据下载完成
- (void)httpConnect:(HTTPConnection *)httpConnect finish:(NSData *)data with:(NSDictionary *)dicParam;

@end


#ifdef DEBUG

#define HTTPLOG(fmt,...)     NSLog((@"HTTP->%s(%d):"fmt),__PRETTY_FUNCTION__,__LINE__,##__VA_ARGS__)

#else

#define HTTPLOG(fmt,...)     NSLog(fmt,##__VA_ARGS__)

#endif


HTTPConnection.m

//
//  HTTPConnection.m
//  
//
//  Created by Jianhong Yang on 12-1-3.
//  Copyright (c) 2012年 __MyCompanyName__. All rights reserved.
//

#import "HTTPConnection.h"


#define  MAXNUMBER_URLCONNECTION           10

#define TASKSTATUS_RUN       @"Run"
#define TASKSTATUS_WAIT      @"Wait"


@interface HTTPConnection (Private)
- (void)startURLConnection;
@end


@implementation HTTPConnection

@synthesize maxNumberOfURLConnection = _maxNumberOfURLConnection;
@synthesize delegate = _delegate;

- (id)init
{
    self = [super init];
    if (self) {
        // Custom initialization.
        _numberOfURLConnection = 0;
        _maxNumberOfURLConnection = MAXNUMBER_URLCONNECTION;
        _marrayTaskDic = [[NSMutableArray alloc] initWithCapacity:5];
    }
    return self;
}

- (void)dealloc
{
    //清空任务
    [self clearRequest];
    //
    [_marrayTaskDic release];
    
    [super dealloc];
}


#pragma mark -
#pragma mark Public

// 根据URL获取Web数据
- (BOOL)requestWebDataWithURL:(NSString *)strURL andParam:(NSDictionary *)dicParam priority:(BOOL)priority
{
    if (nil == dicParam) {
        return NO;
    }
    
    NSURL *url = [NSURL URLWithString:strURL];
    NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url];
    BOOL success = [self requestWebDataWithRequest:request andParam:dicParam priority:priority];
    [request release];
    return success;
}

// 根据URLRequest获取Web数据
- (BOOL)requestWebDataWithRequest:(NSURLRequest *)request andParam:(NSDictionary *)dicParam priority:(BOOL)priority
{
    if (nil == dicParam) {
        return NO;
    }
    //正在处理或等待处理的任务不再接收
    for (NSDictionary *dicTask in _marrayTaskDic) {
        //
        if ([dicParam isEqualToDictionary:[dicTask objectForKey:@"param"]]) {
            HTTPLOG(@"任务重复:%@", dicParam);
            //需优先处理且为等待状态
            if (priority && [[dicParam objectForKey:@"status"] isEqualToString:TASKSTATUS_WAIT]) {
                [dicTask retain];
                [_marrayTaskDic removeObject:dicTask];
                [_marrayTaskDic insertObject:dicTask atIndex:0];
                [dicTask release];
            }
            return NO;
        }
    }
    
    HTTPLOG(@"添加新任务,参数:%@", dicParam);
    NSMutableDictionary *mdicTask = [[NSMutableDictionary alloc] initWithCapacity:3];
    //设置数据缓存
    NSMutableData *mdataCache = [[NSMutableData alloc] init];
    [mdicTask setObject:mdataCache forKey:@"cache"];
    [mdataCache release];
    //参数
    [mdicTask setObject:dicParam forKey:@"param"];
    //状态
    [mdicTask setObject:TASKSTATUS_WAIT forKey:@"status"];
    //创建HTTP网络连接
    NSURLConnection *urlConnection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
    [mdicTask setObject:urlConnection forKey:@"connect"];
    [urlConnection release];
    //保存到数组
    if (priority) {
        [_marrayTaskDic insertObject:mdicTask atIndex:0];
    }
    else {
        [_marrayTaskDic addObject:mdicTask];
    }
    [mdicTask release];
    
    [self startURLConnection];
    return YES;
}

// 取消网络请求
- (BOOL)cancelRequest:(NSDictionary *)dicParam
{
    if (nil == dicParam) {
        return NO;
    }
    //遍历所有任务
    for (int i = 0; i < _marrayTaskDic.count; i++) {
        //查看任务是否相同
        NSDictionary *dicTask = [_marrayTaskDic objectAtIndex:i];
        if ([dicParam isEqualToDictionary:[dicTask objectForKey:@"param"]]) {
            //取消网络请求
            NSURLConnection *connect = [dicTask objectForKey:@"connect"];
            //未启动的须先启动再取消,不然有内存泄露
            if ([TASKSTATUS_WAIT isEqualToString:[dicTask objectForKey:@"status"]]) {
                [connect start];
            }
            [connect cancel];
            //从任务队列中删除
            [_marrayTaskDic removeObjectAtIndex:i];
            _numberOfURLConnection -= 1;
            return YES;
        }
    }
    return NO;
}

// 清空网络请求
- (void)clearRequest
{
    //遍历所有任务
    for (NSDictionary *dicTask in _marrayTaskDic) {
        NSURLConnection *connect = [dicTask objectForKey:@"connect"];
        //未启动的须先启动再取消,不然有内存泄露
        if ([TASKSTATUS_WAIT isEqualToString:[dicTask objectForKey:@"status"]]) {
            [connect start];
        }
        [connect cancel];
        //
        _numberOfURLConnection -= 1;
    }
    //从任务队列中删除
    [_marrayTaskDic removeAllObjects];
}

// 获取已经下载到的数据
- (void)loadReceivedDataOf:(NSDictionary *)dicParam into:(NSMutableData *)mdataReceived
{
    for (NSDictionary *dicTask in _marrayTaskDic) {
        //找到相应的数据
        if ([dicParam isEqualToDictionary:[dicTask objectForKey:@"param"]]) {
            //取出已经下载到的数据
            NSData *data = [dicTask objectForKey:@"cache"];
            if (data.length > 0) {
                [mdataReceived setData:data];
                break;
            }
        }
    }
}


#pragma mark -
#pragma mark NSURLConnectionDataDelegate

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    HTTPLOG(@"网络请求错误:%@", error);
    //找到当前失败的任务
    int indexTask = 0;
    NSDictionary *dicTask = nil;
    for (int i = 0; i < _marrayTaskDic.count; i++) {
        NSDictionary *dic = [_marrayTaskDic objectAtIndex:i];
        //找到网络连接相应的数据字典
        if ([dic objectForKey:@"connect"] == connection) {
            indexTask = i;
            dicTask = [dic retain];
            break;
        }
    }
    //删除失败的任务
    if (dicTask) {
        //删除
        _numberOfURLConnection -= 1;
        [_marrayTaskDic removeObjectAtIndex:indexTask];
        //启动新任务
        [self startURLConnection];
        //通知上层任务失败
        NSDictionary *dicParam = [dicTask objectForKey:@"param"];
        if ([_delegate respondsToSelector:@selector(httpConnect:error:with:)]) {
            [_delegate httpConnect:self error:error with:dicParam];
        }
    }
    [dicTask release];
}

- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    HTTPLOG(@"网络请求收到响应");
    //找到相应的任务
    NSDictionary *dicTask = nil;
    for (int i = 0; i < _marrayTaskDic.count; i++) {
        NSDictionary *dic = [_marrayTaskDic objectAtIndex:i];
        //找到网络连接相应的数据字典
        if ([dic objectForKey:@"connect"] == connection) {
            dicTask = dic;
            break;
        }
    }
    //
    if ([response isMemberOfClass:NSHTTPURLResponse.class]) {
        NSHTTPURLResponse *responseHTTP = (NSHTTPURLResponse *)response;
        NSUInteger statusCode = responseHTTP.statusCode;
        NSDictionary *dicAllHeaderFields = responseHTTP.allHeaderFields;
        NSDictionary *dicParam = [dicTask objectForKey:@"param"];
        //收到服务器返回的HTTP信息头
        SEL receiveResponse = @selector(httpConnect:receiveResponseWithStatusCode:andAllHeaderFields:with:);
        if ([self.delegate respondsToSelector:receiveResponse]) {
            [self.delegate httpConnect:self receiveResponseWithStatusCode:statusCode 
                    andAllHeaderFields:dicAllHeaderFields with:dicParam];
        }
    }
}

- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
    HTTPLOG(@"网络请求收到数据");
    //找到相应的任务
    NSDictionary *dicTask = nil;
    for (int i = 0; i < _marrayTaskDic.count; i++) {
        NSDictionary *dic = [_marrayTaskDic objectAtIndex:i];
        //找到网络连接相应的数据字典
        if ([dic objectForKey:@"connect"] == connection) {
            dicTask = dic;
            break;
        }
    }
    //
    if (dicTask) {
        //向缓存中添加数据
        NSMutableData *mdataCache = [dicTask objectForKey:@"cache"];
        [mdataCache appendData:data];
        NSDictionary *dicParam = [dicTask objectForKey:@"param"];
        HTTPLOG(@"该数据的参数:%@", dicParam);
        //收到部分数据
        if ([self.delegate respondsToSelector:@selector(httpConnect:receiveProgressChanged:with:)]) {
            [self.delegate httpConnect:self receiveProgressChanged:mdataCache.length with:dicParam];
        }
    }
    HTTPLOG(@"网络请求收到数据并处理完成");
}

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    HTTPLOG(@"网络请求完成");
    //找到当前完成的任务
    int indexTask = 0;
    NSDictionary *dicTask = nil;
    for (int i = 0; i < _marrayTaskDic.count; i++) {
        NSDictionary *dic = [_marrayTaskDic objectAtIndex:i];
        //找到网络连接相应的数据字典
        if ([dic objectForKey:@"connect"] == connection) {
            indexTask = i;
            dicTask = [dic retain];
            break;
        }
    }
    //删除已经完成的任务
    if (dicTask) {
        //删除
        _numberOfURLConnection -= 1;
        [_marrayTaskDic removeObjectAtIndex:indexTask];
        //启动新任务
        [self startURLConnection];
        //通知上层完成任务
        NSData *dataCache = [dicTask objectForKey:@"cache"];
        NSDictionary *dicParam = [dicTask objectForKey:@"param"];
        if ([_delegate respondsToSelector:@selector(httpConnect:finish:with:)]) {
            [_delegate httpConnect:self finish:dataCache with:dicParam];
        }
    }
    [dicTask release];
}


#pragma mark - Private

- (void)startURLConnection
{
    if (_numberOfURLConnection < _maxNumberOfURLConnection) {
        if (_numberOfURLConnection < _marrayTaskDic.count) {
            //找到等待状态的任务
            for (NSMutableDictionary *mdicTask in _marrayTaskDic) {
                if ([TASKSTATUS_WAIT isEqualToString:[mdicTask objectForKey:@"status"]]) {
                    //修改状态
                    [mdicTask setObject:TASKSTATUS_RUN forKey:@"status"];
                    //启动
                    NSURLConnection *urlConnection = [mdicTask objectForKey:@"connect"];
                    [urlConnection start];
                    break;
                }
            }
            //
            _numberOfURLConnection += 1;
        }
    }
    HTTPLOG(@"正在处理的网络请求数:%i,等待处理的网络请求:%i", 
            _numberOfURLConnection, _marrayTaskDic.count-_numberOfURLConnection);
}

@end

        这个类有四个接口,后两个是取消网络请求的,不必讨论。前两个是发起网络请求的,用的最多的就是这两个接口了。如果只是通过GET方法从服务器取数据,第一个接口足够了。当然也可以用第二个。如果需要用POST方式向服务器发送数据,得用第二个接口。属性maxNumberOfURLConnection表示同时运行的URL连接数。

   第一个接口的第一个参数是URL字符串,第二个参数用来区分网络请求的,如果两次请求的第二个参数一样,第二次请求会被过滤掉。这个参数还有一个作用,就是协议回调函数的参数,用来让上层区分网络请求的。第三个参数表示是否需要优先处理。

   第二个接口的第一个参数是NSURLRequest类型,用来设置网络请求参数的,比如POST、要发送的数据流、HTTP信息头等。第二个、第三个参数的作用跟第一个接口的第二个、第三个参数意义一样。

   该类对应的协议就不必谈了,大家能看懂的。该类功能的具体实现,大家自己分析。

   有什么问题记得联系我O

抱歉!评论已关闭.