zoukankan      html  css  js  c++  java
  • 利用ASIHTTPRequest实现异步队列

    做过iOS开发应该都有见过ASIHTTPRequest这个强大的HTTP网络请求类库,今天主要来介绍利用ASIHTTPRequest实现异步队列。

    官方地址:http://allseeing-i.com/ASIHTTPRequest/

    github地址:http://github.com/pokeb/asi-http-request/tree

          里面具体可以进行HTTP常见的使用,Get,Post,同步,异步的方式进行请求,里面内嵌一些请求方式,例如ASIWebPageRequest,即WebPage呈现方式;ASIS3Request,即Amazon Simple Storage Service (Amazon S3,http://aws.amazon.com/s3/);ASICloudFilesRequest,即Cloud Files CDN,(http://www.rackspace.com/),这些Request都是继承基础Request,ASIHTTPRequest,包括POST方式,ASPFormDataRequest,里面还内置权限验证,SSL验证以及缓存请求的众多功能,这些功能有兴趣可以下载源代码参考,今天我介绍它的一种Queue的机制,即通过将异步请求放入队列中,进行异步调用,最终队列完后产生一个Queue回调。

          目前,我有一个任务协同办公的web项目,在客户端方面,通过iOS请求Server上的任务列表,并且将任务列表Tasklist同步到了我的客户端的本地数据库中,在每一个任务列表中都有多个任务,相当于任务列表与任务是一对多的关系,由于我在手机端的操作,我将本地更新(修改、添加、删除)的任务更新到本地数据库中,至此我的每一条的任务列表可能都产生了一系列的任务的更新数据,这里不妨这边定义了一个changeLog的变化记录类:

    复制代码
    @interface ChangeLog : NSManagedObject

    @property (nonatomic, retain) NSNumber * changeType;
    @property (nonatomic, retain) NSString * taskId;
    @property (nonatomic, retain) NSString * name;
    @property (nonatomic, retain) NSString * value;

    @end
    复制代码

    这里的taskId就是从server同步下来的任务Id或者本地创建的临时Id,changeType就是更改的类型,例如它可以表示添加、修改、删除等等,name表示实体的字段名称,例如”Subject”,”Body”等等,value就是对应”Subject”,”Body”的值了。

          现在,我想把这些任务的ChangeLog全部同步到Server端,必然在Server上需要相关的API作为支持。假如说,我现在的API的方法是

    Sync(String tasklistId, String changes),相当说,我需要请求两个参数,一个是TasklistId,另外一个在该TasklistId对应的Tasklist上将NSArray的ChangeLog集合,序列化一个JSON字符串,这样Server端获取到数据就可以对changes进行反序列化了。

    编写一个HttpWebRequest的类:

    复制代码
    #import “ASIHTTPRequest.h”
    #import “ASIFormDataRequest.h”
    #import “ASINetworkQueue.h”
    #import “Reachability.h”

    @protocol HttpWebRequestDelegate <NSObject>

    - (void)networkNotReachable;
    - (void)requestFinished:(ASIHTTPRequest *)request;
    - (void)requestFailed:(ASIHTTPRequest *)request;
    - (void)addRequstToPool:(ASIHTTPRequest *)request;
    - (void)queueFinished:(ASINetworkQueue *)queue;
    - (void)notProcessReturned:(NSMutableDictionary*)context;

    @end

    @interface HttpWebRequest : NSObject

    @property(nonatomic,assign) id<HttpWebRequestDelegate> delegate;

    - (ASIFormDataRequest*)createPostRequest:(NSString*)url
    params:(NSMutableDictionary*)params
    headers:(NSMutableDictionary*)headers
    context:(NSMutableDictionary*)context;

    @end
    复制代码

    createPostRequest的实现:

    复制代码
    - (ASIFormDataRequest*)createPostRequest:(NSString*)url
    params:(NSMutableDictionary*)params
    headers:(NSMutableDictionary*)headers
    context:(NSMutableDictionary*)context
    {
    Reachability *reachability = [Reachability reachabilityForInternetConnection];
    [reachability startNotifier];
    if (reachability.currentReachabilityStatus == NotReachable) {
    return nil;
    }
    ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:url]];
    if (context)
    {
    [request setUserInfo:[NSDictionary dictionaryWithDictionary:context]];
    }
    if (headers)
    {
    for (NSString *key in headers.allKeys)
    {
    [request addRequestHeader:key value:[headers objectForKey:key]];
    }
    }
    if(params)
    {
    for(NSString *key in params.allKeys)
    {
    [request setPostValue:[params objectForKey:key] forKey:key];
    }
    }
      
    //cookies设置
    NSHTTPCookieStorage *sharedHTTPCookie = [NSHTTPCookieStorage sharedHTTPCookieStorage];
    //[request setUseCookiePersistence:YES];
    [request setRequestCookies: [NSMutableArray arrayWithArray:sharedHTTPCookie.cookies]];
      
    [request setTimeOutSeconds:SYSTEM_REQUEST_TIMEOUT];
    [request setCachePolicy:ASIAskServerIfModifiedCachePolicy];
      
    [request setValidatesSecureCertificate:NO];
    return request;
    }
    复制代码

    这里我用到一个ASIFormDataRequest的POST请求

    再定义一个TaskService类:

    - (void)syncTasks:(NSMutableArray*)tasklists
    context:(NSMutableDictionary*)context
    delegate:(id)delegate
    {

    }

    这里将本地数据库的ChangeLog变动提交到服务端,假定tasklists已经是从本地数据库取出来的待提交的数据

    在开始实现之前,我们可能会这样写:

    复制代码
    for (Tasklist *tasklist in tasklists)
    {
    //前面进行一些列的本地数据库操作
    NSMutableDictionary *data = [NSMutableDictionary dictionary];
    [data setObject:tasklistId forKey:@”tasklistId”];
    [data setObject:changeLogsJson forKey:@”changes”];

    HttpWebRequest *request = [[HttpWebRequest alloc] init];
    ASIFormDataRequest *postRequest = [request createPostRequest:url params:data headers:nil context:context1];

    [request startAsynchronous];
    }
    复制代码

    startAsynchronous方法就进行一次异步调用,并且通过

    - (void)requestFinished:(ASIHTTPRequest *)request;

    方法进行完成回调。

          但是,这样就会产生一个问题,当你异步请求一个sync_url的时候,这里假如有10条的tasklist,就会产生10条的async,但是你该如何确保它10条都已经执行完毕呢,你也许会想到使用一个原子锁,通过@property (atomic, retain) counter;来实现,但这里,我使用了ASIHTTPRequest内置一个方式就是ASINetworkQueue队列的方式来实现一个Queue的Finish的回调。

    现在我重写定义syncTasks的方法:

    复制代码
    - (void)syncTasks:(NSMutableArray*)tasklists
    context:(NSMutableDictionary*)context
    queue:(ASINetworkQueue*)networkQueue
    delegate:(id)delegate
    {

    }
    复制代码

    这里我多了一个ASINetworkQueue为类型的参数,现在我改写syncTasks的实现:

    复制代码
    networkQueue.delegate = delegate;
    networkQueue.queueDidFinishSelector = @selector(queueFinished:);
    networkQueue.requestDidFinishSelector = @selector(requestFinished:);
    networkQueue.requestDidFailSelector = @selector(requestFailed:);

    for (Tasklist *tasklist in tasklists)
    {
    //前面进行一些列的本地数据库操作
    NSMutableDictionary *data = [NSMutableDictionary dictionary];
    [data setObject:tasklistId forKey:@”tasklistId”];
    [data setObject:changeLogsJson forKey:@”changes”];

    HttpWebRequest *request = [[HttpWebRequest alloc] init];
    ASIFormDataRequest *postRequest = [request createPostRequest:url params:data headers:nil context:context1];

    if(postRequest == nil) {
    [delegate networkNotReachable];
    break;
    }
    [networkQueue addOperation:postRequest];
    [request release];
    }

    [networkQueue go];
    复制代码

          首先,对networkQueue进行一些初始化,例如加入委托,队列完成回调,请求完成回调,错误回调等等,在forin语句中,将每条的postRequest请求加入到该异步队列中[networkQueue addOperation:postRequest];最后通过[networkQueue go];开始执行队列中的异步请求

    这样你就可以在所有request完成之后,即requestFinished回调完成之后,继续执行queueFinished的回调。

    这样就实现了一个异步请求的队列。

    最后调用的代码入口:

    复制代码
    NSMutableDictionary *context = [NSMutableDictionary dictionary];
    [context setObject:@”SyncTasks” forKey:REQUEST_TYPE];
    if(networkQueue)
    {
    [networkQueue reset];
    }
    networkQueue = [ASINetworkQueue queue];
    [taskService syncTasks:tempTasklists context:context queue:networkQueue delegate:self];
    复制代码

    作者:Leepy
     
    邮箱:sunleepy(AT)gmail.com
     
        
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。
  • 相关阅读:
    知方可补不足~Sqlserver发布订阅与sql事务的关系
    基础才是重中之重~泛型类的静态构造方法可不是只执行一次呀
    EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~终结~配置的优化和事务里读写的统一
    EF架构~通过EF6的DbCommand拦截器来实现数据库读写分离~再续~添加对各只读服务器的心跳检测
    windows服务的创建、安装和调试
    Axure RP 实践.1
    实习第一天之数据绑定:<%#Eval("PartyName")%>'
    Hadoop云计算大数据书籍分享
    Android利用setLayoutParams在代码中调整布局(Margin和居中)
    TopCoder中插件的用法
  • 原文地址:https://www.cnblogs.com/greywolf/p/2815611.html
Copyright © 2011-2022 走看看