An NSURLSession works in conjunction with NSURLSessionTasks, which do the actual HTTP calls. These Tasks work asynchronously and deliver data in chunks, so you need some object to setup these tasks, put them to work and wait for their results. The class of this object needs to act as the delegate of the NSURLSessionTasks and therefore needs to implement some delegate protocols:
@interface MyUrlSessionTasksManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate>
...
@end
I have a class that does that. It keeps a list of running tasks and accumulates their retrieved chunked data until they're done. Then it returns its result to the requester, which is technically its delegate. At initialization it creates and configures an NSURLSession (I am using cookies) and an empty list of tasks:
- (id) init {
self = [super init];
if (self) {
self.runningTasks = [NSMutableDictionary dictionary];
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.HTTPShouldSetCookies = YES;
configuration.HTTPCookieAcceptPolicy = NSHTTPCookieAcceptPolicyAlways;
self.session = [NSURLSession sessionWithConfiguration: configuration
delegate: self
delegateQueue: [NSOperationQueue mainQueue]];
}
return self;
}
As mentioned, this class works with a delegate to which to report finished results. Here is the definition of the delegate:
@protocol MyUrlSessionTasksManagerDelegate <NSObject>
- (void) sessionTask: (NSURLSessionTask *) task completedWithError: (NSError *) error data: (NSData *) data;
@end
The main method of this class (for this case) is:
- (NSURLSessionTask *) startPostTaskForURL: (NSURL *) url parameters: (NSDictionary *) values {
NSURLRequest *request = [self createPostRequestWithURL:url parameters:values];
NSURLSessionTask *task = [self.session dataTaskWithRequest:request];
[self scheduleTask:task];
return task;
}
This methods takes an NSURL and an NSDictionary of parameters, creates an HTTP POST request, creates a Task with that request and schedules the task for execution. The scheduling is just putting the task in the dictionary 'runningTasks' with an associated Data object for accumulating the data received:
- (void) scheduleTask: (NSURLSessionTask *) task {
[self.runningTasks setObject:[NSMutableData data] forKey:task];
[task resume];
}
Whenever there is data for a task, the following TaskDelegate methods is called. All it does is lookup the task in its list of running tasks and append the data received to the tasks associated Data object:
- (void) URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
NSMutableData *runningData = [self dataForTask:dataTask];
if (!runningData) {
NSLog(@"No data found for task");
}
[runningData appendData: data];
}
When the data reception is completed the following TaskDelegate method will be called. All it does is report to its delegate, passing the whole Data object and any errors:
- (void) URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
[self.delegate sessionTask:task completedWithError:error data:[self dataForTask:task]];
}
Some internal support methods used:
- (NSMutableData *) dataForTask: (NSURLSessionTask *) task {
return [self.runningTasks objectForKey:task];
}
- (NSString *)urlEncodedUTF8String: (NSString *) source {
return (id)CFBridgingRelease(CFURLCreateStringByAddingPercentEscapes(0, (CFStringRef)source, 0,
(CFStringRef)@";/?:@&=$+{}<>,", kCFStringEncodingUTF8));
}
- (NSString *) createHttpParameters: (NSDictionary *) parameters {
NSMutableString *body = [NSMutableString string];
for (NSString *key in parameters) {
NSString *val = [parameters objectForKey:key];
if ([body length])
[body appendString:@"&"];
[body appendFormat:@"%@=%@", [self urlEncodedUTF8String: [key description]],
[self urlEncodedUTF8String: [val description]]];
}
return body;
}
- (NSURLRequest *)createPostRequestWithURL:(NSURL *)url
parameters:(NSDictionary *)parameters {
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
[request setHTTPMethod:@"POST"];
[request addValue:@"application/x-www-form-urlencoded"
forHTTPHeaderField:@"Content-Type"];
NSString * httpParams = [self createHttpParameters:parameters];
[request setHTTPBody:[httpParams dataUsingEncoding:NSUTF8StringEncoding]];
return request;
}
What is not provided for in this code is how to get the file and convert it to the proper encoding to pass it as a parameter in the POST body. Reason is this code was copied literally from one of my projects, which is not using file uploads. Still I hope it helps you.