HIGH-LEVEL IOS HTTP APIS
2014-02-19 14:35
543 查看
In this section you learn about the high-level APIs most commonly used for HTTP communications from an
iOS application to an HTTP server. There are three primary methods to perform HTTP requests and receive responses using the URL loading system:
Synchronous — The thread on which the initiating code runs blocks until the entire response is loaded and returned to the calling method.
This technique is the simplest to implement but has the most limitations.
Queued asynchronous — The initiating code creates a request and places it on a queue to be performed on a background thread. This method is
slightly more difficult to implement and removes a significant limitation of the pure synchronous technique.
Asynchronous — The initiating code starts a request that runs on the initiating thread but calls delegate methods as the requests proceeds.
This technique is the most complicated to implement but provides the most flexibility in handling responses.
Three types of requests use a combination of four types of objects: NSURL, NSURLRequest,NSURLConnection,
and NSURLResponse.
the example application that performs a synchronous request to load the XML feed.
Best Practices for Synchronous Requests
Only use them on background threads, never on the main thread unless you are completely sure that the request goes to a local file resource.
Only use them when you know that the data returned will never exceed the memory available to the app. Remember that the entire body of the response is returned in-memory to your code. If the response
is large, it may cause out-of-memory conditions in your app. Also remember that your code may duplicate the memory footprint of the returned data when it parses it into a usable format.
Always validate the error and HTTP response status code returned from the call before processing the returned data.
Don’t use synchronous requests if the source URL may require authentication, as the synchronous framework does not support responding to authentication requests. The only exception is forBASIC authentication,
for which credentials can be passed in the URL or request headers. Performing authentication this way increases the coupling between your app and the server, thereby increasing the fragility of the overall application. It can also pass the credentials in clear
text unless the request uses the HTTPS protocol. See Chapter 6, “Securing Network Traffic,” for information on responding to authentication requests.
Don’t use synchronous requests if you need to provide a progress indicator to the users because the request is atomic and
provides no intermediate indications of progress.
Don’t use synchronous requests if you need to parse the response data incrementally via a stream parser.
Don’t use synchronous requests if you may need to cancel the request before it is complete.
Best Practices for Queued Asynchronous Requests
Only use them when you know that the data returned will never exceed the memory available to the app. The entire body of the response is returned in-memory to your code. If the response is large,
it may cause out-of-memory conditions in your app. Remember that your code may duplicate the memory footprint of the returned data when it parses it into a usable format.
Use a single NSOperationQueue for all your operations and control the maximum number of current operations
based on the capacity of your server and the expected network conditions.
Always validate the error and HTTP response status code returned from the call before processing the returned data.
Don’t use them if the source URL may require authentication because this functionality does not support responding to authentication requests. You can put BASIC authentication
credentials in the URL supplied to the request if the service requires that type of authentication.
Don’t use queued asynchronous requests if you need to provide a progress indicator to the users because the request is atomic and provides no intermediate indications of progress.
Don’t use queued asynchronous requests if you need to parse the response data incrementally via a stream parser.
Don’t use queued asynchronous requests if you may need to cancel the request before it is complete.
delegate:
iOS application to an HTTP server. There are three primary methods to perform HTTP requests and receive responses using the URL loading system:
Synchronous — The thread on which the initiating code runs blocks until the entire response is loaded and returned to the calling method.
This technique is the simplest to implement but has the most limitations.
Queued asynchronous — The initiating code creates a request and places it on a queue to be performed on a background thread. This method is
slightly more difficult to implement and removes a significant limitation of the pure synchronous technique.
Asynchronous — The initiating code starts a request that runs on the initiating thread but calls delegate methods as the requests proceeds.
This technique is the most complicated to implement but provides the most flexibility in handling responses.
Three types of requests use a combination of four types of objects: NSURL, NSURLRequest,NSURLConnection,
and NSURLResponse.
Synchronous Requests
the example application that performs a synchronous request to load the XML feed.- (NSArray *) doSyncRequest:(NSString *)urlString { // make the NSURL object from the string NSURL *url = [NSURL URLWithString:urlString]; // Create the request object with a 30 second timeout and a // cache policy to always retrieve the // feed regardless of cachability. NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:30.0]; // Send the request and wait for a response NSHTTPURLResponse *response; NSError *error = nil; NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:&error]; // check for an error if (error != nil) { NSLog(@"Error on load = %@", [error localizedDescription]); return nil; } // check the HTTP status if ([response isKindOfClass:[NSHTTPURLResponse class]]) { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; if (httpResponse.statusCode != 200) { return nil; } } // Parse the data returned into an NSDictionary NSDictionary *dictionary = [XMLReader dictionaryForXMLData:data error:&error]; // Dump the dictionary to the log file NSLog(@"feed = %@", dictionary); NSArray *entries =[self getEntriesArray:dictionary]; // return the list if items from the feed. return entries; }
Best Practices for Synchronous Requests
Only use them on background threads, never on the main thread unless you are completely sure that the request goes to a local file resource.
Only use them when you know that the data returned will never exceed the memory available to the app. Remember that the entire body of the response is returned in-memory to your code. If the response
is large, it may cause out-of-memory conditions in your app. Also remember that your code may duplicate the memory footprint of the returned data when it parses it into a usable format.
Always validate the error and HTTP response status code returned from the call before processing the returned data.
Don’t use synchronous requests if the source URL may require authentication, as the synchronous framework does not support responding to authentication requests. The only exception is forBASIC authentication,
for which credentials can be passed in the URL or request headers. Performing authentication this way increases the coupling between your app and the server, thereby increasing the fragility of the overall application. It can also pass the credentials in clear
text unless the request uses the HTTPS protocol. See Chapter 6, “Securing Network Traffic,” for information on responding to authentication requests.
Don’t use synchronous requests if you need to provide a progress indicator to the users because the request is atomic and
provides no intermediate indications of progress.
Don’t use synchronous requests if you need to parse the response data incrementally via a stream parser.
Don’t use synchronous requests if you may need to cancel the request before it is complete.
Queued Asynchronous Requests
- (void) doQueuedRequest:(NSString *)urlString delegate:(id)delegate { // make the NSURL object NSURL *url = [NSURL URLWithString:urlString]; // create the request object with a no cache policy and a 30 second timeout. NSURLRequest *request = [NSURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:30.0]; // If the queue doesn't exist, create one. if (queue == nil) { queue = [[NSOperationQueue alloc] init]; } // send the request and specify the code to execute when the // request completes or fails. [NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) { if (error != nil) { NSLog(@"Error on load = %@", [error localizedDescription]); } else { // check the HTTP status if ([response isKindOfClass:[NSHTTPURLResponse class]]) { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; if (httpResponse.statusCode != 200) { return; } } // parse the results and make a dictionary NSDictionary *dictionary = [XMLReader dictionaryForXMLData:data error:&error]; NSLog(@"feed = %@", dictionary); // get the dictionary entries. NSArray *entries =[self getEntriesArray:dictionary]; // call the delegate if ([delegate respondsToSelector:@selector(setVideos:)]) { [delegate performSelectorOnMainThread:@selector(setVideos:) withObject:entries waitUntilDone:YES]; } } }]; }
Best Practices for Queued Asynchronous Requests
Only use them when you know that the data returned will never exceed the memory available to the app. The entire body of the response is returned in-memory to your code. If the response is large,
it may cause out-of-memory conditions in your app. Remember that your code may duplicate the memory footprint of the returned data when it parses it into a usable format.
Use a single NSOperationQueue for all your operations and control the maximum number of current operations
based on the capacity of your server and the expected network conditions.
Always validate the error and HTTP response status code returned from the call before processing the returned data.
Don’t use them if the source URL may require authentication because this functionality does not support responding to authentication requests. You can put BASIC authentication
credentials in the URL supplied to the request if the service requires that type of authentication.
Don’t use queued asynchronous requests if you need to provide a progress indicator to the users because the request is atomic and provides no intermediate indications of progress.
Don’t use queued asynchronous requests if you need to parse the response data incrementally via a stream parser.
Don’t use queued asynchronous requests if you may need to cancel the request before it is complete.
Asynchronous Requests
- (void) start { NSLog(@"Starting to download %@", srcURL); // create the URL NSURL *url = [NSURL URLWithString:srcURL]; // Create the request NSURLRequest *request = [NSURLRequest requestWithURL:url]; // create the connection with the target request and this // class as the delegate self.conn = [NSURLConnection connectionWithRequest:request delegate:self]; // start the connection [self.conn start]; }
delegate:
- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse { // Dump debugging information NSLog(@"Redirect request for %@ redirecting to %@", srcURL, request.URL); NSLog(@"All headers = %@", [(NSHTTPURLResponse*) redirectResponse allHeaderFields]); // Follow the redirect return request; }
- (void) connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response { NSLog(@"Received response from request to url %@", srcURL); NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; NSLog(@"All headers = %@", [httpResponse allHeaderFields]); if (httpResponse.statusCode != 200) {// something went wrong, //abort the whole thing // reset the download counts if (downloadSize != 0L) { [progressView addAmountToDownload:-downloadSize]; [progressView addAmountDownloaded:-totalDownloaded]; } [connection cancel]; return; } NSFileManager *fm = [NSFileManager defaultManager]; // If we have a temp file already, close it and delete it if (self.tempFile != nil) { [self.outputHandle closeFile]; NSError *error; [fm removeItemAtPath:self.tempFile error:&error]; } // remove any pre-existing target file NSError *error; [fm removeItemAtPath:targetFile error:&error]; // get the temporary directory name and make a temp file name NSString *tempDir = NSTemporaryDirectory(); self.tempFile = [tempDir stringByAppendingPathComponent: [self createUUID]]; NSLog(@"Writing content to %@", self.tempFile); // create and open the temporary file [fm createFileAtPath:self.tempFile contents:nil attributes:nil]; self.outputHandle = [NSFileHandle fileHandleForWritingAtPath: self.tempFile]; // prime the download progress view NSString *contentLengthString = [[httpResponse allHeaderFields] objectForKey:@"Content-length"]; // reset the download counts if (downloadSize != 0L) { [progressView addAmountToDownload:-downloadSize]; [progressView addAmountDownloaded:-totalDownloaded]; } downloadSize = [contentLengthString longLongValue]; totalDownloaded = 0L; [progressView addAmountToDownload:downloadSize]; }
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data { // figure out how many bytes in this chunk totalDownloaded+=[data length]; // Uncomment the following lines if you want a packet by // packet log of the bytes received. NSLog(@"Received %lld of %lld (%f%%) bytes of data for URL %@", totalDownloaded, downloadSize, ((double)totalDownloaded/(double)downloadSize)*100.0, srcURL); // inform the progress view that data is downloaded [progressView addAmountDownloaded:[data length]]; // save the bytes received [self.outputHandle writeData:data]; }
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error { NSLog(@"Load failed with error %@", [error localizedDescription]); NSFileManager *fm = [NSFileManager defaultManager]; // If you have a temp file already, close it and delete it if (self.tempFile != nil) { [self.outputHandle closeFile]; NSError *error; [fm removeItemAtPath:self.tempFile error:&error]; } // reset the progress view if (downloadSize != 0L) { [progressView addAmountToDownload:-downloadSize]; [progressView addAmountDownloaded:-totalDownloaded]; } }
- (void)connectionDidFinishLoading:(NSURLConnection *)connection { // close the file [self.outputHandle closeFile]; // Move the file to the target location NSFileManager *fm = [NSFileManager defaultManager]; NSError *error; [fm moveItemAtPath:self.tempFile toPath:self.targetFile error:&error]; // Notify any concerned classes that the download is complete [[NSNotificationCenter defaultCenter] postNotificationName:kDownloadComplete object:nil userInfo:nil]; }
Asynchronous Requests and Run Loops
相关文章推荐
- 让Mac轻松访问Windows网络共享
- Nielsen:个人且私人——数字精度对营销商和富裕人群都是双赢
- 在Android上使用tcpdump抓包
- android4.0访问不能网络解决方法
- HttpWebRequest提高效率之连接数,代理,自动跳转,gzip请求等设置问题
- 网络请求
- 人群与网络 第十一周
- Visual studio 中调试oracle数据库的程序,出现“未找到Oracle客户端和网络组件”解决
- CentOS 6.5编译安装httpd-2.4.7
- HttpClient通过代理进行请求
- C# TCP实现多个客户端与服务端 数据 与 文件的传输
- 人群与网络 第十周
- TCP/IP学习笔记二:地址解析协议ARP 数据格式
- win7 共享的问题,"您可能没有权限使用网络资源"的解决办法
- http://search.maven.org/(maven组件找寻)
- HTTP 返回码查询
- Android 通过WebService进行网络编程,使用工具类轻松实现
- node http.get
- 高性能网络编程七--tcp连接的内存使用
- TCP/IP模型的一个简单解释