How to prevent resume the duplicate NSURLSessionTask

时间:2015-08-07 02:02:11

标签: ios networking nsurlsession nsurlsessiontask

I'm trying to use NSURLSession in my project. And here is the situation, I want to check is there any task with the same request already exist. So I use getTasksWithCompletionHandler to check, if there is not, then resume the task in the block. but when I do this way, It's always no other tasks in the array.

did I miss something?

here is my code:

#import "HttpRequestHelper.h"


@implementation HttpRequestHelper

+(NSURLSession *)sharedDefaultSession{
static dispatch_once_t once;
static NSURLSession * defaultSession;
dispatch_once(&once, ^{
    NSURLSessionConfiguration * configure = [NSURLSessionConfiguration defaultSessionConfiguration];
    configure.HTTPMaximumConnectionsPerHost = 5;
    configure.timeoutIntervalForRequest = kTimeOutInterval;
    configure.timeoutIntervalForResource = kTimeOutInterval;
    defaultSession = [NSURLSession sessionWithConfiguration:configure delegate:nil delegateQueue:[NSOperationQueue mainQueue]];
});

return defaultSession;
}

+(void)resultFromRequest:(NSURLRequest *)request withCompleter:(downloadCompleter)completer{

NSURLSessionDataTask * dataTask = [[self sharedDefaultSession] dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
//            NSLog(@"response %@",response);
//            NSLog(@"url:%@\nData:%@",request.URL,[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
    if (!error) {
        NSHTTPURLResponse * httpResponse = (NSHTTPURLResponse *)response;
        if (httpResponse.statusCode == 200) {
            completer([self jsonObjectFromData:data]);
        } else {
            completer(nil);
            // handle http error
        }
    } else {
        completer(nil);
        NSLog(@"network error %@",error.localizedDescription);
        // handle network error
    }
}];

NSLog(@"check %@",dataTask);
[self checkAndResumeTask:dataTask];
}

+(void)checkAndResumeTask:(NSURLSessionTask *)task{
[[self sharedDefaultSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
    BOOL isNewTask = (![self containTask:task inTaskArray:dataTasks]&&![self containTask:task inTaskArray:downloadTasks]);
    NSLog(@"isNewTask : %d %@",isNewTask,[self sharedDefaultSession] );
    if (isNewTask) {
        if (!IS_LOWER_IOS8) {
            task.priority = NSURLSessionTaskPriorityHigh;
        }
        NSLog(@"%@ resume",task);
        [task resume];
    } else {
        [task cancel];
    }
}];
}

+(BOOL)containTask:(NSURLSessionTask *)task inTaskArray:(NSArray *)taskArray{
NSString * taskIndepentId = [task.originalRequest valueForHTTPHeaderField:IndependentID]?:@"";
NSString * taskUrlString = task.originalRequest.URL.absoluteString;
for (NSURLSessionTask * oldTask in taskArray) {
    if (!IS_LOWER_IOS8) {
        oldTask.priority = NSURLSessionTaskPriorityDefault;
    }

    NSString * oldTaskIndepentId = [oldTask.originalRequest valueForHTTPHeaderField:IndependentID]?:@"";
    NSString * oldTaskUrlString = oldTask.originalRequest.URL.absoluteString;
    if ([taskIndepentId isEqualToString:oldTaskIndepentId] && [taskUrlString isEqualToString:oldTaskUrlString] && oldTask!=task) {
        return YES;
    }
}
return NO;
}

+(id)jsonObjectFromData:(NSData*)data{

NSError * dataError;
NSDictionary * dic =   [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&dataError];
if (dataError) {
    NSLog(@"json data error : %@",dataError);
}
return dic;
}

+(void)cancelTaskForRequest:(NSURLRequest *)request{
[[self sharedDefaultSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
    [self cancelRequest:request ForArrayTasks:dataTasks];
    [self cancelRequest:request ForArrayTasks:uploadTasks];
    [self cancelRequest:request ForArrayTasks:downloadTasks];
}];
}

+(void)cancelRequest:(NSURLRequest *)request ForArrayTasks:(NSArray *)arrayTasks{
for (NSURLSessionTask * task in arrayTasks) {
    NSLog(@"task %@",task);
    NSURLRequest * requestTask = task.originalRequest;
    BOOL isSameURL = [requestTask.URL.absoluteString isEqualToString:request.URL.absoluteString];
    BOOL isSameID = [[requestTask valueForHTTPHeaderField:IndependentID] isEqualToString:[request valueForHTTPHeaderField:IndependentID]];
    if (isSameURL && isSameID) {
        [task cancel];
    }
}
}

@end

I have try add [dataTask resume]; before check checkAndResumeTask:, and the tasks will in the array in getTasksWithCompletionHandler, but how can I check before I resume it?

Is this the right way to do?

I will appreciate any comment, thanks.

------- EDIT --------

@dgatwood : I'm sure the other task is running

+(void)checkAndResumeTask:(NSURLSessionTask *)task{
NSLog(@"\ncheck task %@ \nfor URL %@ \nin thread %@",task,task.originalRequest.URL.absoluteString,[NSOperationQueue currentQueue]);
[[self sharedDefaultSession] getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
    NSLog(@"\ncheck task %@ \nfor URL %@ \nin thread %@ \n\n old tasks: %@,\n%@",task,task.originalRequest.URL.absoluteString,[NSOperationQueue currentQueue],dataTasks,downloadTasks);
    BOOL isNewTask = (![self containTask:task inTaskArray:dataTasks]&&![self containTask:task inTaskArray:downloadTasks]);
    NSLog(@"isNewTask : %d %@",isNewTask,[self sharedDefaultSession] );
    if (isNewTask) {
        if (!IS_LOWER_IOS8) {
            task.priority = NSURLSessionTaskPriorityHigh;
        }
        [task resume];
        NSLog(@"\nresume task :%@",task);
    } else {
        [task cancel];
    }
}];
}

I print information in my code, before the block, after the block and after resume task.

and I call three tasks with the same request.

below is my result

you can see after 2015-09-04 01:59:45.216 XXX[26387:1632660] **resume task :<__NSCFLocalDataTask: 0x7fa428e81a40>{ taskIdentifier: 1 } { running }** this task is running, but the block return after this still had no task in the array.

is this because the block already get the array before the first task resume? Or there are something I go wrong?

2015-09-04 01:59:45.130 XXX[26387:1632660] 
check task <__NSCFLocalDataTask: 0x7fa428e81a40>{ taskIdentifier: 1 } { suspended } 
for URL https://XXX/AppApi/api/account/BonusDetails 
in thread <NSOperationQueue: 0x7fa428d05f70>{name = 'NSOperationQueue Main Queue'}
2015-09-04 01:59:45.131 XXX[26387:1632660] 
check task <__NSCFLocalDataTask: 0x7fa42b034e70>{ taskIdentifier: 2 } { suspended } 
for URL https://XXX/AppApi/api/account/BonusDetails 
in thread <NSOperationQueue: 0x7fa428d05f70>{name = 'NSOperationQueue Main Queue'}
2015-09-04 01:59:45.132 XXX[26387:1632660] 
check task <__NSCFLocalDataTask: 0x7fa42b037180>{ taskIdentifier: 3 } { suspended } 
for URL https://XXX/AppApi/api/account/BonusDetails 
in thread <NSOperationQueue: 0x7fa428d05f70>{name = 'NSOperationQueue Main Queue'}
2015-09-04 01:59:45.215 XXX[26387:1632660] 
check task <__NSCFLocalDataTask: 0x7fa428e81a40>{ taskIdentifier: 1 } { suspended } 
for URL https://XXX/AppApi/api/account/BonusDetails 
in thread <NSOperationQueue: 0x7fa428d05f70>{name = 'NSOperationQueue Main Queue'} 

 old tasks: (
),
(
)
2015-09-04 01:59:45.216 XXX1632660] isNewTask : 1 <__NSURLSessionLocal: 0x7fa428e80d80>
2015-09-04 01:59:45.216 XXX[26387:1632660] 
**resume task :<__NSCFLocalDataTask: 0x7fa428e81a40>{ taskIdentifier: 1 } { running }**
2015-09-04 01:59:45.255 XXX[26387:1632660] 
check task <__NSCFLocalDataTask: 0x7fa42b034e70>{ taskIdentifier: 2 } { suspended } 
for URL XXX/AppApi/api/account/BonusDetails 
in thread <NSOperationQueue: 0x7fa428d05f70>{name = 'NSOperationQueue Main Queue'} 

 old tasks: (
),
(
)
2015-09-04 01:59:45.255 XXX[26387:1632660] isNewTask : 1 <__NSURLSessionLocal: 0x7fa428e80d80>
2015-09-04 01:59:45.255 XXX[26387:1632660] 
resume task :<__NSCFLocalDataTask: 0x7fa42b034e70>{ taskIdentifier: 2 } { running }
2015-09-04 01:59:45.256 XXX[26387:1632660] 
check task <__NSCFLocalDataTask: 0x7fa42b037180>{ taskIdentifier: 3 } { suspended } 
for URL https://XXX/AppApi/api/account/BonusDetails 
in thread <NSOperationQueue: 0x7fa428d05f70>{name = 'NSOperationQueue Main Queue'} 

 old tasks: (
),
(
)

0 个答案:

没有答案