NSURLSession methods don't call - ios

I want to download a file from the server by using the NSURLSession instead of NSURLConnection. But when I use it, some of delegate method is not calling and I don't know why.
#import "ViewController.h"
#interface ViewController ()<NSURLSessionDelegate,NSURLSessionDataDelegate,NSURLSessionDownloadDelegate>
#property (strong,nonatomic) NSURLSessionDownloadTask *downloadTask;
#property (strong,nonatomic) NSURLSession *session;
#end
#implementation ViewController
-(void)viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
NSURLSessionConfiguration *backgroundConfiguration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:#"com.webcash.TestingNSURLSession"];
self.session = [NSURLSession sessionWithConfiguration:backgroundConfiguration delegate:self delegateQueue:nil];
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)startDownload:(id)sender {
NSURL *downloadRUL = [NSURL URLWithString:#"http://laguboard.com/music/down/33867378/2794942/NTU0NktpZE56eERWZGxVeC9zTS9LVUd1TEhkZTE0cFZuaW1QS1pFMHVhOUNkM2ZoZEE=/(http://mp3xload.wapka.me).mp3"];
self.downloadTask = [self.session downloadTaskWithURL:downloadRUL];
[self.downloadTask resume];
}
- (IBAction)stopDownload:(id)sender {
}
// ====== THIS METHOD IS NOT CALLING
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
if (totalBytesExpectedToWrite == NSURLSessionTransferSizeUnknown) {
return;
} else {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
double progress = (double)totalBytesWritten / (double)totalBytesExpectedToWrite;
NSLog(#"Downloading progress : %f",progress);
}];
}
}
// ==============
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
if (error != nil) {
NSLog(#"Error : %#",[error localizedDescription]);
} else {
NSLog(#"Download finished");
}
}
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSArray *urls = [fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
NSURL *documentsDirectory = [urls objectAtIndex:0];
NSURL *originalURL = [[downloadTask originalRequest] URL];
NSURL *destinationURL = [documentsDirectory URLByAppendingPathComponent:[originalURL lastPathComponent]];
[fileManager removeItemAtURL:destinationURL error:NULL];
BOOL success = [fileManager copyItemAtURL:location toURL:destinationURL error:&error];
if (success) {
NSLog(#"Download finished");
} else {
NSLog(#"Error : %#",error.description);
}
}
#end
I follow up with many tutorial but it's still not working. please help me to fix this out. thank you.!

#import "ViewController.h"
#interface ViewController ()<NSURLSessionDelegate, NSURLSessionTaskDelegate>
#property (nonatomic, strong) NSMutableData *activeDownload;
#property (nonatomic, strong) NSURLSessionTask *downloadTask;
#property (nonatomic, assign) NSInteger downloadSize;
#property (nonatomic, assign) NSInteger downloadedSize;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (IBAction)startDownload:(id)sender {
self.downloadedSize = 0;
NSURL *nsurl = [NSURL URLWithString:#"http://laguboard.com/music/down/33867378/2794942/NTU0NktpZE56eERWZGxVeC9zTS9LVUd1TEhkZTE0cFZuaW1QS1pFMHVhOUNkM2ZoZEE=/(http://mp3xload.wapka.me).mp3"];
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *downloadSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:nsurl];
self.downloadTask = [downloadSession dataTaskWithRequest:request];
[self.downloadTask resume];
[downloadSession finishTasksAndInvalidate];
}
- (IBAction)stopDownload:(id)sender {
[self.downloadTask cancel];
self.downloadTask = nil;
self.activeDownload = nil;
}
#pragma mark - NSURLSessionDataDelegate methods
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
completionHandler(NSURLSessionResponseAllow);
self.activeDownload = [[NSMutableData alloc] init];
NSString *contentLength = [[(NSHTTPURLResponse *)response allHeaderFields] valueForKey:#"Content-Length"];
self.downloadSize = contentLength.integerValue;
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
[self.activeDownload appendData:data];
self.downloadedSize += [data length];
float downloadProgress = ((float) self.downloadedSize / (float) self.downloadSize) * 100;
//percentage of downloading progress
}
#pragma mark - NSURLSessionTaskDelegate methods
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
if (error != nil) {
NSLog(#"Error : %#",[error localizedDescription]);
} else {
NSLog(#"Download finished");
//the data is in self.activeDownload
}
self.activeDownload = nil;
self.downloadTask = nil;
}
#end

Related

File downloader Using NSURLSessionTask downloadTask

I want to create File download manager to download multiple files with download percent with play pause delete functionality .
I try below code to download multiple file successfully ...but unable to add progress bar please help
for (int i = 0; i < [arr_bookChapter count]; i++) {
NSURLSessionTask * downloadTask = [session downloadTaskWithURL: downloadfileUrl completionHandler: ^ (NSURL * location, NSURLResponse * response, NSError * error) {
if (error == nil) {
NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse * ) response;
if ([httpResponse statusCode] == 200) {
//download file save here
dispatch_queue_t backgroundQueue = dispatch_queue_create("dispatch_queue_#1", 0);
dispatch_async(backgroundQueue, ^ {
dispatch_async(dispatch_get_main_queue(), ^ {
// NSError *error;
//download complete here
});
});
}
} else {
//faile
}
}];
[downloadTask resume];
}
Here i got swift code:
Can someone create or or provide solution for objective-C
You can easily do this, you just need to implement these delegates in your ViewContorller.
<NSURLSessionDataDelegate, NSURLSessionDelegate, NSURLSessionTaskDelegate>
And than you need to follow this code:
#property (nonatomic, retain) NSMutableData *dataToDownload;
#property (nonatomic) float downloadSize;
- (void)viewDidLoad {
[super viewDidLoad];
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: self delegateQueue: [NSOperationQueue mainQueue]];
NSURL *url = [NSURL URLWithString: #"your url"];
NSURLSessionDataTask *dataTask = [defaultSession dataTaskWithURL: url];
[dataTask resume];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
completionHandler(NSURLSessionResponseAllow);
progressBar.progress=0.0f;
_downloadSize=[response expectedContentLength];
_dataToDownload=[[NSMutableData alloc]init];
}
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
[_dataToDownload appendData:data];
progressBar.progress=[ _dataToDownload length ]/_downloadSize;
}

Custom NSURLProtocol slower after switching NSURLConnection to NSURLSession

I have a custom NSURLProtocol ("UrlProtocol") written to intercept requests from a UIWebView when navigating to specific websites, and apply an extra HTTP header before being sent. I followed https://www.raywenderlich.com/59982/nsurlprotocol-tutorial for a working class. My problem comes with switching from the deprecated NSURLConnection to NSURLSession: I tested an extremely simple one-file html page, which loaded successfully. However, slightly more complex sites with resources like js files, images, etc. will timeout, whereas using NSURLConnection the entire site will load within a few seconds.
I'll paste the original UrlProtocol using NSURLConnection, then the new class using NSURLSession. The original:
#import "UrlProtocol.h"
#import "Globals.h"
#implementation UrlProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
if (![request.URL.absoluteString hasPrefix:#"http"]) return NO; //No need to intercept non-http requests
if ([NSURLProtocol propertyForKey:#"handled" inRequest:request]) {
return NO;
}
return YES;
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
NSString* key = #"custom-auth-header";
Globals* globals = [Globals getInstance];
NSString* token = [globals token];
NSMutableURLRequest *newRequest = [request mutableCopy]; //Create a mutable copy that can be modified
[newRequest setValue:token forHTTPHeaderField:key];
return [newRequest copy]; //return a non-mutable copy
}
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a toRequest:(NSURLRequest *)b {
return [super requestIsCacheEquivalent:a toRequest:b];
}
- (void)startLoading {
NSMutableURLRequest *newRequest = [self.request mutableCopy];
[NSURLProtocol setProperty:#YES forKey:#"handled" inRequest:newRequest];
self.connection = [NSURLConnection connectionWithRequest:newRequest delegate:self];
}
- (void)stopLoading {
NSLog(#"stopLoading");
[self.connection cancel];
self.connection = nil;
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response {
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {
[self.client URLProtocol:self didLoadData:data];
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection {
[self.client URLProtocolDidFinishLoading:self];
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {
[self.client URLProtocol:self didFailWithError:error];
}
#end
The new UrlProtocol using NSURLSessionDataTasks for every request:
#import "UrlProtocol.h"
#import "Globals.h"
#implementation UrlProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest * _Nonnull) request {
if (![request.URL.absoluteString hasPrefix:#"http"]) return NO; //No need to intercept non-http requests
if ([NSURLProtocol propertyForKey:#"handled" inRequest:request]) {
return NO;
}
return YES;
}
+ (NSURLRequest * _Nonnull)canonicalRequestForRequest:(NSURLRequest * _Nonnull)request {
NSString* key = #"custom-auth-header";
Globals* globals = [Globals getInstance];
NSString* token = [globals token];
NSMutableURLRequest *newRequest = [request mutableCopy]; //Create a mutable copy that can be modified
[newRequest setValue:token forHTTPHeaderField:key];
return [newRequest copy]; //return a non-mutable copy
}
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest * _Nonnull)a toRequest:(NSURLRequest * _Nonnull)b {
return [super requestIsCacheEquivalent:a toRequest:b];
}
- (void)startLoading {
NSMutableURLRequest *newRequest = [self.request mutableCopy];
[NSURLProtocol setProperty:#YES forKey:#"handled" inRequest:newRequest];
[Globals setUrlSessionDelegate:self];
Globals* globals = [Globals getInstance];
self.dataTask = [globals.session dataTaskWithRequest:newRequest];
[self.dataTask resume];
}
- (void)URLSession:(NSURLSession * _Nonnull)session dataTask:(NSURLSessionDataTask * _Nullable)dataTask didReceiveData:(NSData * _Nullable)data{
[self.client URLProtocol:self didLoadData:data];
}
- (void)URLSession:(NSURLSession * _Nonnull)session dataTask:(NSURLSessionDataTask * _Nullable)dataTask didReceiveResponse:(NSURLResponse * _Nullable)response
completionHandler:(void (^ _Nullable)(NSURLSessionResponseDisposition))completionHandler{
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
completionHandler(NSURLSessionResponseAllow);
}
- (void)URLSession:(NSURLSession * _Nonnull)session task:(NSURLSessionTask * _Nonnull)task didCompleteWithError:(NSError * _Nullable)error{
if (error){
[self.client URLProtocol:self didFailWithError:error];
} else {
[self.client URLProtocolDidFinishLoading:self];
}
}
- (void)URLSession:(NSURLSession * _Nonnull)session task:(NSURLSessionTask * _Nonnull)task willPerformHTTPRedirection:(NSHTTPURLResponse * _Nonnull)response
newRequest:(NSURLRequest * _Nonnull)request completionHandler:(void (^ _Nonnull)(NSURLRequest * _Nullable))completionHandler {
completionHandler(request);
}
- (void)stopLoading {
[self.dataTask cancel];
self.dataTask = nil;
}
#end
"Globals" is a singleton where I have initialized one NSURLSession meant to be used throughout the runtime of the app. It also contains the token I set as a custom HTTP header for all requests:
#import "Globals.h"
#import "UrlProtocol.h"
#implementation Globals
#synthesize token;
#synthesize session;
static Globals *instance = nil;
+(Globals*) getInstance
{
#synchronized(self)
{
if (instance == nil)
{
instance = [Globals new];
}
}
return instance;
}
//UrlProtocol class has no init method, so the NSURLSession delegate is being set on url load. We will ensure only one NSURLSession is created.
+(void) setUrlSessionDelegate:(UrlProtocol*) urlProtocol{
Globals* globals = [Globals getInstance];
if (!globals.session){
globals.session = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.defaultSessionConfiguration delegate:urlProtocol delegateQueue:nil];
}
}
#end
Solved my problem by creating a new default NSURLSession for each NSURLSessionDataTask. Something was wrong with the way I was trying to share one NSURLSession for all my tasks. URLProtocol's startLoading method is now as follows:
- (void)startLoading {
NSMutableURLRequest *newRequest = [self.request mutableCopy];
[NSURLProtocol setProperty:#YES forKey:#"handled" inRequest:newRequest];
NSURLSessionConfiguration* config = NSURLSessionConfiguration.defaultSessionConfiguration;
NSURLSession* session = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil];
self.dataTask = [session dataTaskWithRequest:newRequest];
[self.dataTask resume];
}
The simple HTML page test before must have worked because only one task was needed to load the page

NSURLSession: can't get resume data after calling cancelByProducingResumeData

I want to resume downloading after user cancels downloading or something wrong happens. But when I call cancelByProducingResumeData method, the resumeData is nil. So, I can't resume downloading. I'm sure the download link can be resumed, because our PC client can resume downloading of this link.
Here is my code. Here is the full project.
#import "ViewController.h"
#interface ViewController ()
{
NSURLSession *_session;
}
#property (weak, nonatomic) IBOutlet UIProgressView *progressView;
#property NSURLSessionDownloadTask *netTask;
#property NSData *resumeData;
#end
#implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
if (_session == nil) {
NSURLSessionConfiguration *confi = [NSURLSessionConfiguration defaultSessionConfiguration];
_session = [NSURLSession sessionWithConfiguration:confi delegate:self delegateQueue:[NSOperationQueue mainQueue]];
}
}
- (IBAction)startAction:(id)sender {
[self start];
}
- (IBAction)stopActon:(id)sender {
[self stop];
}
- (void)stop {
__weak typeof(self) vc = self;
[self.netTask cancelByProducingResumeData:^(NSData * _Nullable resumeData) {
vc.resumeData = resumeData;
vc.netTask = nil;
}];
}
- (void)start {
if (self.resumeData != nil) {
self.netTask = [_session downloadTaskWithResumeData:self.resumeData];
} else {
NSURL *downlaodURL = [NSURL URLWithString:#"http://sdl24.yunpan.cn/share.php?method=Share.download&cqid=37ef0df7c8155bacf55c237bd433ddd8&dt=24.02b6cbb4148de503fe35ddab08dac35b&e=1459317290&fhash=41181b28ff97806ef8469842b4a5eabc330a0c60&fname=feistudy%2B%2B%25E8%25AF%25AD%25E8%25A8%2580%25E5%25AD%25A6%25E4%25B9%25A0%25E6%2596%25B9%25E6%25B3%2595%25E8%25AE%25BA%25E8%25BF%25B0&fsize=87624815&nid=14471440239484082&st=e08142ab7c935cdd15ecc8851c82e819&xqid=22309244"];
self.netTask = [_session downloadTaskWithURL:downlaodURL];
}
[self.netTask resume];
}
- (NSString*)filePath
{
NSString *doc = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
NSString *path = [doc stringByAppendingPathComponent:#"p.rmvb"];
return path;
}
#pragma mark - NSURLSessionDownloadDelegate
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
dispatch_async(dispatch_get_main_queue(), ^{
NSFileManager *manager = [NSFileManager defaultManager];
[manager moveItemAtPath:location.path toPath:[self filePath] error:nil];
NSLog(#"locaton.path:%#", location.path);
NSLog(#"filePaht:%#",[self filePath]);
});
}
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
dispatch_async(dispatch_get_main_queue(), ^{
double progress = totalBytesWritten/(double)totalBytesExpectedToWrite;
NSLog(#"progress:%f",progress);
self.progressView.progress = progress;
});
}
#pragma mark - NSURLSessionTaskDelegate
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
didCompleteWithError:(nullable NSError *)error
{
if (error) {
NSData *resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData];
self.resumeData = resumeData;
}
}
#end
There's a long list of requirements for when resume data can be obtained. Among other things:
The response must contain an ETag or Last-Modified header.
I think the response must also contain an Accept-Ranges: bytes header
The temporary file must still exist (not low on disk space).
It must be an HTTP or HTTPS request.
The Last-Modified or ETag header must indicate that the file hasn't changed since it was last requested.
There might be other requirements that I'm forgetting, e.g. HTTP/1.1.

NSURLSession delegate implementation returns only <head> of html

Let's go straight into code.
First in appDelegate, I register my connection protocol:
[NSURLProtocol registerClass:[MyURLConnection class]];
Here's what my connection class looks like:
+(BOOL)canInitWithRequest:(NSURLRequest *)request {
return YES;
}
-(void)startLoading {
if (self.cachedResponse) {
NSLog(#"there is a cached response %#", self.cachedResponse);
}
MyNetworkSession *task = [MyNetworkSession new];
task.request = self.request;
task.urlClient = self.client;
task.isDataTask = YES;
task.isBackgroundSession = YES;
[task start];
}
-(void)stopLoading {
// nothing here
}
Now, MyNetworkSession is the delegate for NSURLSession tasks, like so:
// ----------- MyNetworkSession.h
#interface MyNetworkSession : NSObject
<NSURLSessionDelegate,
NSURLSessionTaskDelegate,
NSURLSessionDataDelegate>
-(void) start;
#end
//------------ MyNetworkSession.m
#implementation MyNetworkSession {
NSURLSessionDataTask *_dataTask;
NSURLSessionDownloadTask *_downloadTask;
}
// create session
-(NSURLSession*) session {
static NSURLSession *session = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSURLSessionConfiguration *backgroundConfiguration = [
NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:
BACKGROUND_SESSION_IDENTIFIER];
backgroundConfiguration.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
session = [NSURLSession
sessionWithConfiguration:backgroundConfiguration
delegate:self
delegateQueue:nil];
});
return session;
}
// start download/data task
-(void)start {
if (self.isDataTask){
_dataTask = [self.session dataTaskWithRequest:self.request];
[_dataTask resume];
}
}
#pragma mark- delegate methods
-(void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
didCompleteWithError:(NSError *)error {
if (error) {
NSLog(#"Error in connection %# for task %#", error, task.response.URL);
}
NSLog(#"completed response %#", task.response.URL.absoluteString);
_dataTask = nil;
_downloadTask = nil;
[self.urlClient URLProtocolDidFinishLoading:self.urlClient];
}
-(void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveResponse:(NSURLResponse *)response
completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler {
NSLog(#"received response %#", response.URL.absoluteString);
[self.urlClient URLProtocol:self.urlClient
didReceiveResponse:responsecacheStoragePolicy:NSURLCacheStorageAllowedInMemoryOnly];
completionHandler(NSURLSessionResponseAllow);
}
-(void)URLSession:(NSURLSession *)session
dataTask:(NSURLSessionDataTask *)dataTask
didReceiveData:(NSData *)data {
NSLog(#"received data %#", dataTask.response.URL.absoluteString);
if (!self.data) {
self.data = [data mutableCopy];
} else {
[self.data appendData:data];
}
[self.urlClient URLProtocol:self.urlClient didLoadData:self.data];
}
//... some more methods
#end
That's all the relevant code I guess.
The problem is that when I see the response in a webview, I only get the <head> tag of the document.
I am not getting the rest of the html. And also, the js/css files listed in the <head> tag are not downloaded. Do you see any flaw in the implementation?

can NSURLProtocol work with NSURLSession {upload, download}dataTask

I have a custom NSURLProtocol
#import <Foundation/Foundation.h>
#interface XXXURLProtocol : NSURLProtocol <NSURLSessionDataDelegate, NSURLSessionTaskDelegate>
#property (nonatomic, strong) NSURLSession *session;
#property (nonatomic, strong) NSURLSessionTask *task;
#end
#import "XXXURLProtocol.h"
#implementation DXYURLProtocol
+ (BOOL)canInitWithRequest:(NSURLRequest *)request {
if ([NSURLProtocol propertyForKey:YXURLProtocolHandled inRequest:request]) {
return NO;
}
NSString *scheme = [[request URL] scheme];
NSDictionary *dict = [request allHTTPHeaderFields];
return [dict objectForKey:#"custom_header"] == nil &&
([scheme caseInsensitiveCompare:#"http"] == NSOrderedSame ||
[scheme caseInsensitiveCompare:#"https"] == NSOrderedSame);
}
+ (NSURLRequest *)canonicalRequestForRequest:(NSURLRequest *)request {
return request;
}
+ (BOOL)requestIsCacheEquivalent:(NSURLRequest *)a
toRequest:(NSURLRequest *)b {
return [super requestIsCacheEquivalent:a toRequest:b];
}
- (void)startLoading
{
NSMutableURLRequest *mutableReqeust = [[self request] mutableCopy];
//add custom headers
[XXXURLProtocol addCustomHeaders:mutableReqeust];
[NSURLProtocol setProperty:#(YES)
forKey:YXURLProtocolHandled
inRequest:mutableReqeust];
NSURLSessionConfiguration *config;
config = [NSURLSessionConfiguration defaultSessionConfiguration];
config.protocolClasses = #[ self ];
self.session = [NSURLSession sessionWithConfiguration:config];
self.task = [self.session dataTaskWithRequest:mutableReqeust];
[self.task resume];
}
- (void)stopLoading
{
[self.task cancel];
self.task = nil;
}
//and all other NSURLProtocolClient protocol method
#end
how to make this custom NSURLProtocol to support {upload, download}dataTask?
You have the right idea, but you need to implement some key URLSessionDelegate methods to pass the response and data up to the NSURLProtocol client:
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
if( error ) {
[self.client URLProtocol:self didFailWithError:error];
} else {
[self.client URLProtocolDidFinishLoading:self];
}
}
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
[self.client URLProtocol:self didReceiveResponse:response cacheStoragePolicy:NSURLCacheStorageNotAllowed];
completionHandler(NSURLSessionResponseAllow);
}
-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
[self.client URLProtocol:self didLoadData:data];
}

Resources