The interface of a simple proxy class
The following code fragment is based on the interface shown in Listing 1-1
Listing 1-1
#import <Foundation/Foundation.h>typedef void (^CompletionHandlerType)();@interface MySessionDelegate : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>@property NSURLSession *backgroundSession;@property NSURLSession *defaultSession;@property NSURLSession *ephemeralSession;#if TARGET_OS_IPHONE@property NSMutableDictionary *completionHandlerDictionary;#endif- (void) addCompletionHandler: (CompletionHandlerType) handler forSession: (NSString *)identifier;- (void) callCompletionHandlerForSession: (NSString *)identifier;@end
Create and configure a session
Nsurlsession provides a number of configuration options:
- Supports private storage of caches, cookies, certificates, and specific protocols for single-session sessions
- Authentication associated to a specific request (task), or a set of requests (sessions)
- Upload or download files via URLs, supporting the splitting of metadata into short data based on file content
- Configure the maximum number of connections per host
- Configure a time-out when resources cannot be downloaded within a certain time
- Version interval that supports secure Transport Layer protocol (TLS)
- Custom Proxy
- Management strategies for Cookies
- HTTP Transport Management
Most of the configuration is set in a configuration object, and some basic settings can be generalized. Initializing a Session object requires specifying the following information:
- A configuration object used to manage the behavior of a session or task
- Optionally, a proxy object is used to indicate the progress of receiving data, session tasks or other events of the session, such as server authentication, determining whether a load request can be converted to a download request, etc.
If you do not specify a proxy, the Nsurlsession object uses the system-provided proxy. In this way, you can easily use nsurlsession instead of the existing sendasynchronousrequest:queue: Completionhandler: Method.
注意:如果app需要在后台进行数据传输,必须使用自定义代理.
After creating a session object, it is no longer possible to modify its configuration objects and proxies, in addition to recreating a session.
Listing 1-2 shows sample code for creating a default session, a staging session, and a background session
#if target_os_iphoneself.completionhandlerdictionary = [Nsmutabledictionary dictionarywithcapacity:0]; #endif/* Create some configuration objects. */nsurlsessionconfiguration *backgroundconfigobject = [nsurlsessionconfiguration backgroundSessionConfiguration: @ " Mybackgroundsessionidentifier "]; Nsurlsessionconfiguration *defaultconfigobject = [Nsurlsessionconfiguration defaultsessionconfiguration]; Nsurlsessionconfiguration *ephemeralconfigobject = [Nsurlsessionconfiguration ephemeralsessionconfiguration];/* Configure caching behavior for the default session. Note that IOS requires the cache path to is a path relative to the ~/library/caches directory, and OS X expects an ABS Olute path. */#if target_os_iphonensstring *cachepath = @ "/mycachedirectory"; Nsarray *mypathlist = Nssearchpathfordirectoriesindomains (Nscachesdirectory, Nsuserdomainmask, YES); NSString *mypath = [Mypathlist objectatindex:0]; NSString *bundleidentifier = [[NSBundle mainbundle] bundleidentifier]; NSString *FULLCAchepath = [[MyPath stringbyappendingpathcomponent:bundleidentifier] stringbyappendingpathcomponent:cachepath]; NSLog (@ "Cache path:%@\n", Fullcachepath), #elseNSString *cachepath = [Nstemporarydirectory () stringbyappendingpathcomponent:@ "/nsurlsessiondemo.cache"]; NSLog (@ "Cache path:%@\n", CachePath), #endifNSURLCache *mycache = [[Nsurlcache alloc] initwithmemorycapacity:16384 diskcapacity:268435456 Diskpath:cachepath];d efaultconfigobject.urlcache = Mycache; Defaultconfigobject.requestcachepolicy = nsurlrequestuseprotocolcachepolicy;/* Create a session for each Configurations. */self.defaultsession = [Nsurlsession sessionwithconfiguration:defaultconfigobject delegate:self delegateQueue: [ Nsoperationqueue mainqueue]];self.backgroundsession = [nsurlsession sessionwithconfiguration: Backgroundconfigobject delegate:self delegatequeue: [Nsoperationqueue mainqueue]];self.ephemeralsession = [ Nsurlsession sessionwithconfiguration:ephemeralconfigobject delegate:self delegatequeue: [NSOperaTionqueue Mainqueue]];
In addition to the background configuration object (background configurations), you can reuse the configuration object to create additional sessions. (A background configuration object cannot be reused because two background sessions cannot use the same identifier identifier)
You can modify a configuration object safely at any time. Because when a session is created, the configuration object is passed by a deep copy, so the modification affects only the session that was created, and does not affect the session that already exists. For example, You might want to create another session that can only re-connect data in a WiFi environment, as shown in 1-3:
Listing 1-3 reusing a configuration object
ephemeralConfigObject.allowsCellularAccess = YES;// ...NSURLSession *ephemeralSessionWiFiOnly = [NSURLSession sessionWithConfiguration: ephemeralConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];
Fetching resources using system-provided proxies
The simplest and most straightforward way to use nsurlsession is to replace the previous SendAsynchronousRequest:queue:completionHandler: method. To do this, you need to implement two code in the app:
- Create a configuration object, and a session object based on that configuration object
- A completion handler to handle the data received after the completion of the things to do
With system-provided proxies, you can fetch specific URLs with one line of code per request. Listing 1-4 is an example of the simplest implementation.
注意:系统提供的代理仅仅实现了有限网络功能.如果app的需求超出了基本的URL加载,比如自定义认证或者数据后台下载,那么需要实现一个完整的代理,参见URL Session的生命周期.
Listing 1-4 uses the system-supplied proxy request resource:
NSURLSession *delegateFreeSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];[[delegateFreeSession dataTaskWithURL: [NSURL URLWithString: @"http://www.example.com/"] completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSLog(@"Got response %@ with error %@.\n", response, error); NSLog(@"DATA:\n%@\nEND DATA\n", [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding]); }] resume];
Fetching data using custom proxies
Retrieving data using a custom proxy must implement the following methods:
- URLSession:dataTask:didReceiveData: Provides data returned by a task request, periodically returning a block of data
- URLSession:task:didCompleteWithError: Indicates whether the data is complete and received
If the app needs to use the data after the URLSession:dataTask:didReceiveData: method returns, the data storage must be implemented in code.
For example, a Web browser might need to render the currently received data based on the data received previously. To do this, you can use a Nsmutabledata object to store the resulting data, and then use AppendData: To stitch the currently received data into the previously received data.
Listing 1-5 is an example of how to create a data task to start:
NSURL *url = [NSURL URLWithString: @"http://www.example.com/"];NSURLSessionDataTask *dataTask = [self.defaultSession dataTaskWithURL: url];[dataTask resume];
Download file
On some programs, downloading files is similar to receiving data. The app should implement the following proxy methods:
- URLSession:downloadTask:didFinishDownloadingToURL: A temporary storage directory to download content for your app. Note: Before this method returns, you must open the file to read or move the download to a permanent directory. When the method returns, the temporary file is deleted.
- URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesExpectedToWrite: Provides status information for the download progress.
- URLSession:downloadTask:didResumeAtOffset:expectedTotalBytes: Tell the app to try to recover a previously failed download.
- URLSession:task:didCompleteWithError: Tell app download failed
If the download task is scheduled in a background session, the download behavior will continue during the app's non-run period. If the download task is scheduled in the system default session or in a temporary session, the download will restart when the app restarts.
During data transfer with the server, if the user pauses, the app can call the Cancelbyproducingresumedata: method to cancel the task. Then, The app can pass the transferred data as a parameter to Downloadtaskwithresumedata: or Downloadtaskwithresumedata:completionhandler: To create a new download task to continue the download.
Listing 1-6 samples The download of a large file. Listing 1-7 samples the agent method for the download task.
Listing 1-6 Download Task example:
NSURL *url = [NSURL URLWithString: @"https://developer.apple.com/library/ios/documentation/Cocoa/Reference/" "Foundation/ObjC_classic/FoundationObjC.pdf"];NSURLSessionDownloadTask *downloadTask = [self.backgroundSession downloadTaskWithURL: url];[downloadTask resume];
Listing 1-7 Download the agent method for the task:
-(void) Urlsession: (Nsurlsession *) session Downloadtask: (Nsurlsessiondownloadtask *) downloadtask Didfinishdownloadingtourl: (Nsurl *) location{NSLog (@ "Session%@ download task%@ finished downloading to URL%@\n", SE Ssion, Downloadtask, location); #if 0/* workaround */[self callcompletionhandlerforsession: Session.configuration.identifier]; #endif # define Read_the_file 0#if read_the_file/* Open The newly downloaded FILE for Reading. */nserror *err = nil; Nsfilehandle *FH = [nsfilehandle filehandleforreadingfromurl:location error: &err];/* Store This file handle SOMEWH Ere, and read data from it. *///. #elseNSError *err = nil; Nsfilemanager *filemanager = [Nsfilemanager Defaultmanager]; NSString *cachedir = [[Nshomedirectory () stringbyappendingpathcomponent:@ "Library"] stringbyappendingpathcomponent: @ "Caches"]; Nsurl *cachedirurl = [Nsurl fileurlwithpath:cachedir];if ([FileManager moveitematurl:location ToURL:cacheDirURL Erro R: &err]) {/* Store some reference to thE New URL */} else {/* Handle the error. */} #endif}-(void) Urlsession: (Nsurlsession *) session Downloadtask: (Nsurlsessio Ndownloadtask *) Downloadtask didwritedata: (int64_t) Byteswritten Totalbyteswritten: (int64_t) TotalBytesWritten Totalbytesexpectedtowrite: (int64_t) totalbytesexpectedtowrite{NSLog (@ "Session%@ download Task%@ wrote an additional% LLD bytes (total%lld bytes) Out of an expected%LLD bytes.\n ", Session, Downloadtask, Byteswritten, Totalbyteswritten, Totalbytesexpectedtowrite);} -(void) Urlsession: (Nsurlsession *) session Downloadtask: (Nsurlsessiondownloadtask *) Downloadtask Didresumeatoffset :(int64_t) Fileoffset expectedtotalbytes: (int64_t) expectedtotalbytes{NSLog (@ "Session%@ Download Task%@ resumed at off Set%lld bytes out of a expected%LLD bytes.\n ", Session, Downloadtask, Fileoffset, expectedtotalbytes);}
Uploading data content
The app can provide the HTTP POST request body in three ways: NSData objects, files, and streams. In general, apps should:
- Using a NSData object, if the data already exists in memory, and the data is not unreasonably destroyed.
- In the form of files, if the content to be uploaded is stored on the hard disk by a file, or the content to be uploaded is written to the file, if this resolves the memory.
- Use a stream, if it is to receive data from the network, or convert existing Nsurlconnection code that provides the stream.
Whichever method you choose, you should implement URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend if the app provides a custom proxy: method to get the upload progress.
In addition, if the app uses a stream as the request body, it must also provide a custom session Broker implementation URLSession:task:needNewBodyStream: method that details the uploading of data through the stream
Uploading using NSData objects
Using the NSData object to upload data, the app needs to call Uploadtaskwithrequest:fromdata: or UploadTaskWithRequest:fromData:completionHandler: To create an upload task and pass the NSData object that will be uploaded to the Fromdata parameter.
The Session object calculates the content length based on the NSData object, and the Content-length.app that is assigned to the request header also provides the request header information that the server may need in the URL request object-for example, content type.
Upload using File Form
Using file upload, the app needs to call Uploadtaskwithrequest:fromfile: or UploadTaskWithRequest:fromFile:completionHandler: method to create an upload task, and a file path to read the content.
The Session object automatically calculates Content-length, and if the app does not provide Content-type, the session object will automatically generate one. The app also provides the request header information that the server may need in the URL request object
Upload using stream form
Using the stream to upload information, the app needs to call the Uploadtaskwithstreamedrequest: method to create an upload task. The app provides a request object that is bound to a stream. The app also needs to be in the URL The Request object provides the requested header information that the server may need, such as Content-type and Content-length.
In addition, because the session object is not guaranteed to be able to read data from the provided stream, the app needs to provide a new stream for the session to re-request (for example, authentication failed). The app needs to implement URLSession:task:needNewBodyStream: Method. When this method is called, the app needs to get or create a new stream, and then call the completed processing block provided.
注意:因为app必须实现URLSession:task:needNewBodyStream:方法,所以这种形式不支持使用系统默认的代理.
Use download tasks to upload files
When the download task is created, the app needs to provide an NSData object or a stream as a parameter to the Nsurlrequest object.
If you use data flow, the app needs to implement the URLSession:task:needNewBodyStream: method to handle authentication failures. Detailed description of uploading data through the stream
Process authentication and secure transport acknowledgement
If the remote server returns a status value indicating that authentication or authentication is required for a specific environment (such as an SSL client certificate), the Nsurlsession call invokes an authentication-related proxy method.
- Session level: NSURLAUTHENTICATIONMETHODNTLM, Nsurlauthenticationmethodnegotiate, Nsurlauthenticationmethodclientcertificate, or Nsurlauthenticationmethodservertrust, the session object calls the session proxy method Urlsession: Didreceivechallenge:completionhandler:. If the app does not provide a session proxy, the session object invokes the task with the proxy method URLSession:task:didReceiveChallenge: Completionhandler:.
- Non-session level: The Nsurlsession object calls the session proxy method URLSession:task:didReceiveChallenge:completionHandler:. If the app provides a session broker, and the app needs to process authentication, Then you have to work at the task level. At non-session level, URLSession:didReceiveChallenge:completionHandler: is not called.
See Authentication challenges and TLS Chain Validation for more information.
Working with iOS background activities
Using Nsurlsession in iOS, the app will restart automatically when a download task is completed. App Agent Method Application:handleeventsforbackgroundurlsession: Completionhandler: Responsible for rebuilding the appropriate session, storing the completion processor, and calling the completion processor when the session object invokes the session proxy's urlsessiondidfinisheventsforbackgroundurlsession: method.
Listing 1-8, listing 1-9, respectively, examples of these sessions and the app proxy method
Checklist 1-8,ios Session proxy method for background download
#if target_os_iphone-(void) Urlsessiondidfinisheventsforbackgroundurlsession: (nsurlsession *) session{ NSLog (@ "Background URL session%@ finished events.\n", session); if (session.configuration.identifier) [Self callcomplet IonHandlerForSession:session.configuration.identifier];} -(void) Addcompletionhandler: (completionhandlertype) handler forsession: (NSString *) identifier{if ([ Self.completionhandlerdictionary Objectforkey:identifier]) {NSLog (@ "Error:got multiple handlers for a single session Identifier. This should not happen.\n ");} [Self.completionhandlerdictionary Setobject:handler forkey:identifier];} -(void) Callcompletionhandlerforsession: (NSString *) Identifier{completionhandlertype handler = [ Self.completionhandlerdictionary Objectforkey:identifier];if (handler) {[Self.completionhandlerdictionary Removeobjectforkey:identifier]; NSLog (@ "Calling completion handler.\n"); Handler (); }} #endif
Checklist 1-9,ios App proxy method for background download
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler{ NSURLSessionConfiguration *backgroundConfigObject = [NSURLSessionConfiguration backgroundSessionConfiguration: identifier];NSURLSession *backgroundSession = [NSURLSession sessionWithConfiguration: backgroundConfigObject delegate: self.mySessionDelegate delegateQueue: [NSOperationQueue mainQueue]];NSLog(@"Rejoining session %@\n", identifier);[ self.mySessionDelegate addCompletionHandler: completionHandler forSession: identifier];}
Reprint Please specify source: http://blog.csdn.net/qq329735967
Any questions welcome email to [email protected]
Official Apple document translation: Using Nsurlsession (ii)