zoukankan      html  css  js  c++  java
  • ASIHTTPRequest足够了吗?

            大家都知道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
    
    @property (nonatomic, assign) int maxNumberOfURLConnection;
    @property (nonatomic, assign) id <HTTPConnectionDelegate> delegate;
    
    // 判断指定参数的网络请求是否存在
    - (BOOL)requestIsExist:(NSDictionary *)dicParam;
    
    // 指定url是否在请求中
    - (BOOL)urlIsRequesting:(NSString *)url;
    
    // 根据URL获取Web数据
    // dicParam 可用于回传数据。不得为空
    - (BOOL)requestWebDataWithURL:(NSString *)strURL andParam:(NSDictionary *)dicParam;
    
    // 根据URLRequest获取Web数据
    // dicParam 可用于回传数据。不得为空
    - (BOOL)requestWebDataWithRequest:(NSURLRequest *)request andParam:(NSDictionary *)dicParam;
    
    // 取消网络请求
    - (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 receivePartData:(NSData *)partData 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,...)     
    
    #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 () {
        NSMutableArray *_marrayTaskDic;
    }
    @property (nonatomic, assign) int numberOfURLConnection;
    @end
    
    
    @implementation HTTPConnection
    
    - (id)init
    {
        self = [super init];
        if (self) {
            // Custom initialization.
            self.numberOfURLConnection = 0;
            self.maxNumberOfURLConnection = MaxNumber_URLConnection;
            _marrayTaskDic = [[NSMutableArray alloc] initWithCapacity:5];
        }
        return self;
    }
    
    - (void)dealloc
    {
        // 清空任务
        self.delegate = nil;
        [self clearRequest];
        //
    #if __has_feature(objc_arc)
    #else
        [_marrayTaskDic release];
        
        [super dealloc];
    #endif
    }
    
    
    #pragma mark - Public
    
    // 判断指定参数的网络请求是否存在
    - (BOOL)requestIsExist:(NSDictionary *)dicParam
    {
        for (NSDictionary *dicTask in _marrayTaskDic) {
            //
            if ([dicParam isEqualToDictionary:dicTask[@"param"]]) {
                return YES;
            }
        }
        return NO;
    }
    
    // 指定url是否在请求中
    - (BOOL)urlIsRequesting:(NSString *)url
    {
        for (NSDictionary *dicTask in _marrayTaskDic) {
            //
            NSURLConnection *connect = dicTask[@"connect"];
            if ([[[connect originalRequest].URL description] isEqualToString:url]) {
                return YES;
            }
        }
        return NO;
    }
    
    // 根据URL获取Web数据
    // dicParam 可用于回传数据。不得为空
    - (BOOL)requestWebDataWithURL:(NSString *)strURL andParam:(NSDictionary *)dicParam
    {
        if (nil == dicParam) {
            return NO;
        }
    
        // 实例化NSMutableURLRequest
        NSURL *url = [NSURL URLWithString:strURL];
        NSMutableURLRequest *mURLRequest = [NSMutableURLRequest requestWithURL:url];
        [mURLRequest setCachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData];
        [mURLRequest setTimeoutInterval:10.0f];
        // 开始请求数据
        return [self requestWebDataWithRequest:mURLRequest andParam:dicParam];
    }
    
    // 根据URLRequest获取Web数据
    // dicParam 可用于回传数据。不得为空
    - (BOOL)requestWebDataWithRequest:(NSURLRequest *)request andParam:(NSDictionary *)dicParam
    {
        // 非主线程取数据,直接同步获取,然后通过协议回调
        if ([NSThread currentThread] != [NSThread mainThread]) {
            NSURLResponse *response = nil;
            NSError *error = nil;
            NSData *dataAD = [NSURLConnection sendSynchronousRequest:request
                                                   returningResponse:&response
                                                               error:&error];
            [self.delegate httpConnect:self finish:dataAD with:dicParam];
            return YES;
        }
        if (nil == dicParam) {
            return NO;
        }
        // 正在处理或等待处理的任务不再接收
        for (NSDictionary *dicTask in _marrayTaskDic) {
            //
            if ([dicParam isEqualToDictionary:dicTask[@"param"]]) {
                HTTPLog(@"任务重复:%@", dicParam);
                return NO;
            }
        }
        
        HTTPLog(@"添加新任务,参数:%@", dicParam);
        NSMutableDictionary *mdicTask = [NSMutableDictionary dictionary];
        // 设置数据缓存
        NSMutableData *mdataCache = [NSMutableData data];
        [mdicTask setObject:mdataCache forKey:@"cache"];
        // 参数
        [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"];
    #if __has_feature(objc_arc)
    #else
        [urlConnection release];
    #endif
        // 将下载任务保存到数组
        [_marrayTaskDic addObject:mdicTask];
        
        [self startURLConnection];
        return YES;
    }
    
    // 取消网络请求
    - (BOOL)cancelRequest:(NSDictionary *)dicParam
    {
        if (nil == dicParam) {
            return NO;
        }
        // 遍历所有任务
        for (int i = 0; i < _marrayTaskDic.count; i++) {
            // 查看任务是否相同
            NSDictionary *dicTask = _marrayTaskDic[i];
            if ([dicParam isEqualToDictionary:dicTask[@"param"]]) {
                // 取消网络请求
                NSURLConnection *connect = dicTask[@"connect"];
                // 未启动的须先启动再取消,不然有内存泄露
                if ([TaskStatus_Wait isEqualToString:dicTask[@"status"]]) {
                    [connect start];
                }
                else {
                    self.numberOfURLConnection -= 1;
                }
                [connect cancel];
                // 从任务队列中删除
                [_marrayTaskDic removeObjectAtIndex:i];
                return YES;
            }
        }
        return NO;
    }
    
    // 清空网络请求
    - (void)clearRequest
    {
        // 遍历所有任务
        for (NSDictionary *dicTask in _marrayTaskDic) {
            NSURLConnection *connect = dicTask[@"connect"];
            // 未启动的须先启动再取消,不然有内存泄露
            if ([TaskStatus_Wait isEqualToString:dicTask[@"status"]]) {
                [connect start];
            }
            else {
                self.numberOfURLConnection -= 1;
            }
            [connect cancel];
        }
        // 从任务队列中删除
        [_marrayTaskDic removeAllObjects];
    }
    
    
    #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[i];
            // 找到网络连接相应的数据字典
            if (dic[@"connect"] == connection) {
                indexTask = i;
                dicTask = dic;
                break;
            }
        }
        // 删除失败的任务
        if (dicTask) {
            // 删除
            NSDictionary *dicTempTask = [NSDictionary dictionaryWithDictionary:dicTask];
            self.numberOfURLConnection -= 1;
            [_marrayTaskDic removeObjectAtIndex:indexTask];
            // 启动新任务
            [self startURLConnection];
            // 通知上层任务失败
            if ([self.delegate respondsToSelector:@selector(httpConnect:error:with:)]) {
                [self.delegate httpConnect:self error:error with:dicTempTask[@"param"]];
            }
        }
    }
    
    - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
    {
        HTTPLog(@"网络请求收到响应");
        // 找到相应的任务
        NSDictionary *dicTask = nil;
        for (int i = 0; i < _marrayTaskDic.count; i++) {
            NSDictionary *dic = _marrayTaskDic[i];
            // 找到网络连接相应的数据字典
            if (dic[@"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[@"param"];
            // 收到服务器返回的HTTP信息头
            if ([self.delegate respondsToSelector:@selector(httpConnect:receiveResponseWithStatusCode:andAllHeaderFields:with:)]) {
                [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[i];
            // 找到网络连接相应的数据字典
            if (dic[@"connect"] == connection) {
                dicTask = dic;
                break;
            }
        }
        //
        if (dicTask) {
            // 向缓存中添加数据
            NSMutableData *mdataCache = dicTask[@"cache"];
            [mdataCache appendData:data];
            NSDictionary *dicParam = dicTask[@"param"];
            HTTPLog(@"该数据的参数:%@", dicParam);
            // 收到部分数据
            if ([self.delegate respondsToSelector:@selector(httpConnect:receivePartData:with:)]) {
                [self.delegate httpConnect:self receivePartData:data 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[i];
            // 找到网络连接相应的数据字典
            if (dic[@"connect"] == connection) {
                indexTask = i;
                dicTask = dic;
                break;
            }
        }
        // 删除已经完成的任务
        if (dicTask) {
            // 删除
            NSDictionary *dicTempTask = [NSDictionary dictionaryWithDictionary:dicTask];
            self.numberOfURLConnection -= 1;
            [_marrayTaskDic removeObjectAtIndex:indexTask];
            // 启动新任务
            [self startURLConnection];
            // 通知上层完成任务
            if ([self.delegate respondsToSelector:@selector(httpConnect:finish:with:)]) {
                NSData *dataCache = dicTempTask[@"cache"];
                NSDictionary *dicParam = dicTempTask[@"param"];
                [self.delegate httpConnect:self finish:dataCache with:dicParam];
            }
        }
    }
    
    
    #pragma mark - ()
    
    - (void)startURLConnection
    {
        if (self.numberOfURLConnection < self.maxNumberOfURLConnection) {
            if (self.numberOfURLConnection < _marrayTaskDic.count) {
                // 找到等待状态的任务
                for (NSMutableDictionary *mdicTask in _marrayTaskDic) {
                    if ([TaskStatus_Wait isEqualToString:mdicTask[@"status"]]) {
                        // 修改状态
                        [mdicTask setObject:TaskStatus_Run forKey:@"status"];
                        // 启动
                        NSURLConnection *urlConnection = mdicTask[@"connect"];
                        [urlConnection start];
                        break;
                    }
                }
                self.numberOfURLConnection += 1;
            }
        }
        HTTPLog(@"正在处理的网络请求数:%@,等待处理的网络请求:%@",
                @(self.numberOfURLConnection), @(_marrayTaskDic.count-self.numberOfURLConnection));
    }
    
    @end
    

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

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

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

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

       有什么问题记得联系我O




    最新版本请到Demo中查看:

    Demo地址:https://github.com/yjh4866/ExceedMVC



  • 相关阅读:
    Vue.js 2.0更新之增加Virtual DOM讲解
    Json串的单引号和双引号引发的问题解析
    理解javascript中的Function.prototype.bind的方法
    微信小程序开源项目库汇总
    PYTHON.redis_day02
    PYTHON.redis_day01
    PYTHON3.AJAX_day02
    PYTHON3.day01_Ajax
    PYTHON3.django_day08(见pdf)
    PYTHON3.django_day07(见pdf)
  • 原文地址:https://www.cnblogs.com/yjh4866/p/6253873.html
Copyright © 2011-2022 走看看