刚开始研究ASIHTTPRequest,目前似乎有很多人在用这个,但是没有找到完整的翻译文档,没事翻译一下,水平有限,还请多多指教。。。
已有 2 人评分技术分 收起 理由
guess303 + 10 很给力!
jackiehu + 1 赞一个!正需要这个

总评分: 技术分 + 11   查看全部评分

研究员 2# dymx101 发表于 2011-9-27 16:38:39
原文:
Creating and running requests
Creating a synchronous request

The simplest way to use ASIHTTPRequest. Sending the startSynchronous message will execute the request in the same thread, and return control when it has completed (successfully or otherwise).

Check for problems by inspecting the error property.

To get the response as a string, call the responseString method. Don’t use this for binary data - use responseData to get an NSData object, or, for larger files, set your request to download to a file with the downloadDestinationPath property.

- (IBAction)grabURL:(id)sender
{
  NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
  ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
  [request startSynchronous];
  NSError *error = [request error];
  if (!error) {
    NSString *response = [request responseString];
  }
}

In general, you should use asynchronous requests in preference to synchronous requests. When you use ASIHTTPRequest synchronously from the main thread, your application’s user interface will lock up and become unusable for the duration of the request.

译文:

创建和运行请求

创建一个同步请求

这是最简单的用法,发送 startSynchronous 消息将在相同线程中执行请求,不管是否成功,完成后返回控制。
查看error属性以检测问题。
要以字符串形式得到响应,就调用responseString方法。这个方法不适合二进制数据 - 你应该使用responseData 得到NSData对象,或者如果有更大的文件,你可以设置downloadDestinationPath将请求下载到文件。


- (IBAction)grabURL:(id)sender
{
  NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
  ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
  [request startSynchronous];
  NSError *error = [request error];
  if (!error) {
    NSString *response = [request responseString];
  }
}

注意:一般的,你应该优先使用异步请求,如果你在主线程中使用ASIHTTPRequest的同步方法,程序的ui在请求过程中将被锁定而无法响应。
版主 3# newbie 发表于 2011-9-27 16:38:43
强烈支持,不过翻译稿在哪里?
研究员 4# dymx101 发表于 2011-9-27 16:40:43
原文地址在:http://allseeing-i.com/ASIHTTPRequest/How-to-use
为了简介期间,后面不再贴原文了。
研究员 5# dymx101 发表于 2011-9-27 16:41:01
创建一个异步请求

下面的代码做同样的事情,但请求运行于后台。

- (IBAction)grabURLInBackground:(id)sender
{
   NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
   ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
   [request setDelegate:self];
   [request startAsynchronous];
}

- (void)requestFinished:(ASIHTTPRequest *)request
{
   // Use when fetching text data
   NSString *responseString = [request responseString];

   // Use when fetching binary data
   NSData *responseData = [request responseData];
}

- (void)requestFailed:(ASIHTTPRequest *)request
{
   NSError *error = [request error];
}

注意我们设置请求的委托,这样就能在请求完成或失败时得到通知。
这是创建异步请求最简单的方式,他会运行于场景后面的一个全局的NSOperationQueue中,对于更复杂的操作,例如在多个请求中追踪进展,你可能想要创建自己的队列,下面我们谈谈这个。
研究员 6# dymx101 发表于 2011-9-27 16:41:15
使用程序块(blocks)
对于v1.8,我们可以在支持程序块的平台使用他们:

- (IBAction)grabURLInBackground:(id)sender
{
   NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
   __block ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
   [request setCompletionBlock:^{
      // Use when fetching text data
      NSString *responseString = [request responseString];

      // Use when fetching binary data
      NSData *responseData = [request responseData];
   }];
   [request setFailedBlock:^{
      NSError *error = [request error];
   }];
   [request startAsynchronous];
}

注意:在我们声明请求时,用到了__block限定语,这很重要!它告诉block不要保留请求,来防止一个保留循环(retain-cycle),因为请求总会保留block.
研究员 7# dymx101 发表于 2011-9-27 16:41:44
使用队列

这个例子做同样的事,不同的是,我们为自己的请求创建了NSOperationQueue。

使用一个NSOperationQueue或者ASINetworkQueue,你能更有效的控制异步请求。我们使用一个请求,只有一定数量的请求能同时运行。如果你添加多于maxConcurrentOperationCount数量的请求,这些请求将等到其他请求完成后才会开始。

- (IBAction)grabURLInTheBackground:(id)sender
{
   if (![self queue]) {
      [self setQueue:[[[NSOperationQueue alloc] init] autorelease]];
   }

   NSURL *url = [NSURL URLWithString:@"http://allseeing-i.com"];
   ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
   [request setDelegate:self];
   [request setDidFinishSelector:@selector(requestDone:)];
   [request setDidFailSelector:@selector(requestWentWrong:)];
   [[self queue] addOperation:request]; //queue is an NSOperationQueue
}

- (void)requestDone:(ASIHTTPRequest *)request
{
   NSString *response = [request responseString];
}

- (void)requestWentWrong:(ASIHTTPRequest *)request
{
   NSError *error = [request error];
}


在上面的例子中,'queue'是控制器的一个保留的NSOperationQueue属性。

我们设置自定义的selector处理成功或失败的回调。如果你不设置这些,默认的requestFinished和requestFailed将被使用,就像在之前的例子中一样。

在委托方法中处理对歌请求的成功和失败

如果你需要处理许多不同类型的请求,你有几个选择:

1. 如果你的请求都属于一个大的范围,你又想区别他们,可以设置请求的userInfo字典属性,填入你的自定义数据,你就可以在委托方法中读取了。在更简单的用例中,你可以简单的设置tag属性。这些属性都是给你自己用的,不会发送到服务器。

2. 如果你处理完全不同的请求,为每个请求设置不同的 setDidFinishSelector / setDidFailSelector。

3. 对更复杂的情况,或者你想在后台解析响应数据,可以为每个请求类型创建一个ASIHTTPRequest的子类,然后重载requestFinished: 和 failWithError: 。

注意:最好避免在委托方法中,用url来区分不同的请求,因为url属性在重定向时会改变。如果你真的真的想用的话,请用[request originalURL] 代替,这个将总是记录第请求连接时的首个url。
研究员 8# dymx101 发表于 2011-9-27 16:42:08
关于ASINetworkQueues

ASINetworkQueues是NSOperationQueue,它提供了额外的功能。
它的主要目的是追踪整个队列上传或下载的进度。
ASINetworkQueues提供了一些额外的委托方法selector。
requestDidStartSelector
每当队列中的一个请求开始运行时调用。你可以使用这个作为didStartSelector的替代方法,为你加到队列的请求设置一个委托。

requestDidReceiveResponseHeadersSelector
每当队列中的一个请求从服务器得到响应头时调用。对于大的下载,这个 selector有时在请求实际完成前执行。
你可以使用它作为对didReceiveResponseHeadersSelector的替代。

requestDidFinishSelector
每当队列中的一个请求完成时调用。可以使用它作为对didFinishSelector的替代。

requestDidFailSelector
每当队列中的请求失败时调用,可作为didFailSelector的替代。

queueDidFinishSelector
当队列完成时调用,不管单个请求成功或失败。

使用以上selector,要将队列的委托,而不是请求的委托,设置到实现这些selector所代表的方法的控制器。

ASINetworkQueues工作起来和NSOperationQueues稍有不同,加到其中的请求不会立刻运行,当使用ASINetworkQueue时,添加你想运行的所有请求,然后调用[queue go]。当你启动一个队列,将精确进度(accurate progress)打开时,他会首先为队列中所有的get请求执行一个head请求,来得到将要下载数据的总体尺寸。获得此数据后,它就能准确的显示总体进度,然后真实的请求才会开始。
问题:当你向一个运行中的ASINetworkQueue加入一个请求时发生了什么事情?
回答:如果你使用ASINetworkQueue来追踪几个请求的总体进度,整体进度只会在哪个请求开始执行时,才会将它计算在内。ASINetworkQueue不会在运行中,当加入请求后执行head请求,所以如果你立刻向运行的队列加入许多请求,总体进度不会立刻更新。
如果队列已经运行,你不需要再次调用[queue go]。

当ASINetworkQueue中的一个请求失败,队列默认的将取消所有其他的请求。你可以调用[queue setShouldCancelAllRequestsOnFailure:NO].来关闭这一行为。
ASINetworkQueues只能执行ASIHTTPRequest操作,而不能用于一般操作,尝试添加一个非ASIHTTPRequest的NSOperation将产生一个异常。
提示:这里有一个创建和使用ASINetworkQueue的完整例子:
http://gist.github.com/150447


补充内容 (2011-9-27 16:42):
未完待续。。。
研究员 9# dymx101 发表于 2011-9-27 16:47:40
newbie 发表于 2011-9-27 16:38
强烈支持,不过翻译稿在哪里?

俺是翻一段贴一段的。。。
高级构架师 10# guess303 发表于 2011-9-27 17:03:55
谢谢大侠!
研究员 11# dymx101 发表于 2011-9-27 18:34:21
取消一个异步请求
为了取消一个异步请求,可以调用[request cancel],不管该请求是用[request startAsynchronous] 启动的,还是在你创建的队列中运行。注意你不能取消一个同步请求。
注意,当你取消一个请求,请求会将之视为一个错误,然后会调用你的委托或者队列的失败委托方法。如果你不想这种事发生,在取消之前将委托设为nil,或者使用clearDelegatesAndCancel作为代替。

// Cancels an asynchronous request
[request cancel]

// Cancels an asynchronous request, clearing all delegates and blocks first
[request clearDelegatesAndCancel];

当使用一个ASINetworkQueue时,你取消其中一个请求,所有其他的请求也会被取消,除非队列的shouldCancelAllRequestsOnFailure为no, 默认为yes。

// When a request in this queue fails or is cancelled, other requests will continue to run
[queue setShouldCancelAllRequestsOnFailure:NO];

// Cancel all requests in a queue
[queue cancelAllOperations];
研究员 12# dymx101 发表于 2011-9-27 18:34:40
安全处理委托在请求完成前释放的情况

请求不会保留他们的委托,所以如果你的委托有机会在请求运行时释放的话,你能及时清理请求的委托属性是至关重要的。在大多数情况下,如果你的委托将要释放,你大概也想取消请求,因为你不再关心请求的状态。

在下面的例子中,控制器有一个保存于保留实例变量中的ASIHTTPRequest对象。我们在其dealloc实现中调用clearDelegatesAndCancel方法,在我们释放请求的引用之前:

// Ddealloc method for our controller
- (void)dealloc
{
   [request clearDelegatesAndCancel];
   [request release];
   ...
   [super dealloc];
}
研究员 13# dymx101 发表于 2011-9-27 18:35:21
发送数据

发送请求头
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request addRequestHeader:@"Referer" value:@"http://allseeing-i.com/"];

用ASIFormDataRequest发送一个表单

要以兼容web页表单的方式发送post数据,可以使用ASIFormDataRequest的子类。数据以‘application/x-www-form-urlencoded’格式寄出,或者用‘multipart/form-data’格式上传二进制数据或文件。文件中的数据按照需要从磁盘读取,所以发送大文件是没问题的,只要你的web服务器设置了如何处理他们。
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:@"Ben" forKey:@"first_name"];
[request setPostValue:@"Copsey" forKey:@"last_name"];
[request setFile:@"/Users/ben/Desktop/ben.jpg" forKey:@"photo"];

ASIFormDataRequest使用setFile:forKey:添加文件时将自动侦测文件的mime类型(ios3.0之后),并包含这个到发送到服务器的mime头部中。如果你愿意,你可以使用更长的重载形式:
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];

// Upload a file on disk
[request setFile:@"/Users/ben/Desktop/ben.jpg" withFileName:@"myphoto.jpg" andContentType:@"image/jpeg"
forKey:@"photo"];

// Upload an NSData instance
[request setData:imageData withFileName:@"myphoto.jpg" andContentType:@"image/jpeg" forKey:@"photo"];

你可以为同一个参数发送多个值使用其他的add api:
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request addPostValue:@"Ben" forKey:@"names"];
[request addPostValue:@"George" forKey:@"names"];
[request addFile:@"/Users/ben/Desktop/ben.jpg" forKey:@"photos"];
[request addData:imageData withFileName:@"george.jpg" andContentType:@"image/jpeg" forKey:@"photos"];

参考ASIFormDataRequest.h,了解添加到你post的参数的所有方法的完整列表。
研究员 14# dymx101 发表于 2011-9-27 18:35:38
put方法和自定义post
如果你想通过put发送数据,或者想要发送post,但是想自己创建post数据体(body),使用appendPostData: 或者 appendPostDataFromFile:。

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request appendPostData:[@"This is my data" dataUsingEncoding:NSUTF8StringEncoding]];
// Default becomes POST when you use appendPostData: / appendPostDataFromFile: / setPostBody:
[request setRequestMethod:@"PUT"];

如果你想发送大量的数据,并且不用ASIFormDataRequest,参看后面的‘从磁盘以流式post数据’小节。
研究员 15# dymx101 发表于 2011-9-27 19:41:15
下载数据

将响应数据直接下载为文件

如果你请求的数据相当大,你可以直接将下载内存直接保存为文件。这样,ASIHTTPRequest不需要一次在内存中保存整个请求。

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDownloadDestinationPath:@"/Users/ben/Desktop/my_file.txt"];

当使用downloadDestinationPath下载到文件时,下载过程中,数据将被保存在一个临时文件中。这个文件路径保存于temporaryFileDownloadPath。当请求成功完成,下面的事情之一会发生:

如果数据时gzip压缩过的,压缩文件将被解压到downloadDestinationPath,并且临时文件被删除;
如果数据没被压缩,临时文件移动到downloadDestinationPath,覆盖掉任何之前的文件。

注意:如果响应body是空的,文件是不会被创建的。所以如果请求可能返回一个空的body,你要确定在尝试操作文件之前,检查它是否存在。
研究员 16# dymx101 发表于 2011-9-27 19:41:49
处理收到的响应数据

如果你需要处理收到的响应数据,比如你想使用流解析器(streaming parser)来解析仍在下载的响应数据,就需要在委托中实现request:didReceiveData:方法。注意当你这么做时,ASIHTTPRequest不会产生responseData,也不会将数据写入downloadDestinationPath - 你必须自己搞定保存响应数据的事。

读取HTTP状态码

ASIHTTPRequest 不会鸟大多数的http状态码,重定向和验证的状态码除外。所以,就要靠你检查问题,比如404错误,然后确定你做了恰当的处理。

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
int statusCode = [request responseStatusCode];
NSString *statusMessage = [request responseStatusMessage];


读取响应头

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSString *poweredBy = [[request responseHeaders] objectForKey:@"X-Powered-By"];
NSString *contentType = [[request responseHeaders] objectForKey:@"Content-Type"];


处理文本编码
ASIHTTPRequest会尝试从Content-Type头得到数据的编码。如果它发现了一个编码类型,他会社子responseEncoding为相应的NSStringEncoding。如果它没在头部发现编码信息,就会用defaultResponseEncoding,这个值默认为NSISOLatin1StringEncoding。
当你调用[request responseString],ASIHTTPRequest将尝试用responseEncoding作为源编码,从收到的数据创建一个字符串。

处理重定向
当ASIHTTPRequest碰到以下http状态码时,会自动重定向到一个新的url,假设Location头已经发送:
301 永久移动
302 发现
303 参看其他
当重定向发生,响应数据(responseHeaders / responseCookies / responseData / responseString 等) 的值将反映从最终位置收到的内容。
在重定向周期中碰到的任何url上设置的Cookie,都倍存储到全局cookie仓库,在恰当的时候会由重定向请求呈现给服务器。
你可以关闭自动重定向,设置shouldRedirect属性为no即可。

注意:默认情况下,自动重定向总是以get方式进行请求(没有body)。这个行为复合大多数的浏览器,除了象301和302这样应该用原有方式重定向的规范。
为了保留301和302的原有方式(包含请求的body),需要将shouldUseRFC2616RedirectBehaviour设置为yes,在你开始请求之前。

补充内容 (2011-9-27 19:50):
文档真的很长啊。。。才翻译了1/4,今天歇菜,明天继续。。。
中级工程师 17# redow 发表于 2011-9-27 20:19:02
太给力了,收藏之
研究员 18# dymx101 发表于 2011-9-28 10:56:40
跟踪进度

每个ASIHTTPRequest都有两个用于跟踪进度的委托 - downloadProgressDelegate用于下载,uploadProgressDelegate用于上传。
进度委托可以是NSProgressIndicators(Mac OS X)或者UIProgressViews(iPhone)。ASIHTTPRequest会自动适应这两者行为上的差异。你也能够使用自定义的类作为进度委托,只要它响应setProgress:方法。

如果你正执行单个请求,在这个请求上设置一个上传或下载委托。
如果你在队列中执行多个请求,并且想跟踪队列中所有请求的总体进度,可以使用ASINetworkQueue并设置队列的进度委托
如果想同时做上面两件事,也是可行的。

重点注意:如果你正在向需要验证的站点进行上传操作,为了提供有效验证,每当上传失败时,进度会被重设为之前的值。为此,如果你正同验证web服务器通信,建议你仅当useSessionPersistence为yes时使用上传进度委托,并确保你在尝试跟踪大量上传数据前,在另一个请求中验证。

当请求body小于128kb时,目前是不能够跟踪上传进度的。对请求大于128kb的请求,进度委托不会收到第一个128kb的post数据进度的信息。这是因为CFNetwork API的限制造成的。
2009.6.21日更新:apple的好家伙非常友好的定位了我的bug报告!在iphone 2.0 sdk中,貌似这个缓冲尺寸减小到了32kb,这让精确的上传进度跟踪更加可靠了。
研究员 19# dymx101 发表于 2011-9-28 10:58:40

跟踪单个请求的下载进度

在这个例子中,myProgressIndicator是一个NSProgressIndicator。

ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDownloadProgressDelegate:myProgressIndicator];
[request startSynchronous];
NSLog(@"Max: %f, Value: %f", [myProgressIndicator maxValue],[myProgressIndicator doubleValue]);

跟踪一组请求的下载进度

这个例子中,myProgressIndicator 是一个UIProgressView,myQueue是一个ASINetworkQueue。
- (void)fetchThisURLFiveTimes:(NSURL *)url
{
   [myQueue cancelAllOperations];
   [myQueue setDownloadProgressDelegate:myProgressIndicator];
   [myQueue setDelegate:self];
   [myQueue setRequestDidFinishSelector:@selector(queueComplete:)];
   int i;
   for (i=0; i<5; i++) {
      ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
      [myQueue addOperation:request];
   }
   [myQueue go];
}

- (void)queueComplete:(ASINetworkQueue *)queue
{
   NSLog(@"Value: %f", [myProgressIndicator progress]);
}

注意对于ASINetworkQueues,我们必须调用[myQueue go]来启动队列。

跟踪单个请求的上传进度

本例中,myProgressIndicator是一个UIProgressView。
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:@"Ben" forKey:@"first_name"];
[request setPostValue:@"Copsey" forKey:@"last_name"];
[request setUploadProgressDelegate:myProgressIndicator];
[request startSynchronous];
NSLog(@"Value: %f",[myProgressIndicator progress]);

跟踪一组请求的上传进度

本例中,myProgressIndicator是一个NSProgressUbdicator,myQueue是一个ASINetworkQueue。
- (void)uploadSomethingFiveTimes:(NSURL *)url
{
   [myQueue cancelAllOperations];
   [myQueue setUploadProgressDelegate:myProgressIndicator];
   [myQueue setDelegate:self];
   [myQueue setRequestDidFinishSelector:@selector(queueComplete:)];
   int i;
   for (i=0; i<5; i++) {
      ASIHTTPRequest *request = [ASIFormDataRequest requestWithURL:url];
      [request setPostBody:[@"Some data" dataUsingEncoding:NSUTF8StringEncoding]];
      [myQueue addOperation:request];
   }
   [myQueue go];
}

- (void)queueComplete:(ASINetworkQueue *)queue
{
   NSLog(@"Max: %f, Value: %f", [myProgressIndicator maxValue],[myProgressIndicator doubleValue]);
}
研究员 20# dymx101 发表于 2011-9-28 10:59:14

精确进度vs简单进度

ASIHTTPRequest提供了两种显示进度的途径,简单进度 和 精确进度。他们由ASIHTTPRequests 和 ASINetworkQueues的showAccurateProgress来控制。如果你在一个请求上设置showAccurateProgress,只会影响这个请求。如果你设置了队列,将影响到队列的全部请求。

简单请求
当你使用简单进度,进度仅在请求完成时更新。对于单个进程,你只能得到0%和100%完成。对于一个包括4个请求的队列,你能得到5次进度更新,0%,25%,50%,75%和100%,每一次增量表明有一个请求完成了。
简单进度(showAccurateProgress = NO)是ASINetworkQueues的默认值,它很好的适用于包含大量的轻量级上传/下载请求的队列。

精确进度
使用精确进度时,进度以收发的字节来更新,所以极适合收发大量数据的请求,它会更好的指示一个耗时请求收发了多少数据。
使用精确进度会稍稍降低上传操作的性能,因为进度委托(可能是UIProgressView或者NSProgressIndicator)将更为频繁的重绘。
使用精确进度会对使用队列的下载任务影响更大,因为队列在下载前,会先为其中的get请求执行head请求,来决定将要下载的数据总体尺寸。强烈推荐你在队列中下载大文件时使用精确进度,但是应该避免队列中包含大量小型下载时使用它。
精确进度(showAccurateProgress = YES)是ASIHTTPRequests执行同步任务时的默认值。
您需要登录后才可以回帖 登录 | 注册

关于我们|手机版|Archiver|DEVDIV.COM ( 京ICP备07040843号 )  

GMT+8, 2012-5-19 16:18

Powered by DEVDIV.COM!

© 2010-2012 DEVDIV.COM Coummunity.

回顶部