0

I seem to be running into trouble. For some reason, If I try to check the class type of my NSURLSessionTask objects, it doesn't work at all. If I check their taskDescription properties, this works of course if I set them before initiating the task. I would just like to know why the below code doesn't work for me. I appreciate any help offered!

- (void)uploadIt
{
    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    defaultConfigObject.timeoutIntervalForResource = 15.0;
    defaultConfigObject.requestCachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;

    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:[NSOperationQueue mainQueue]];

    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

    NSURLSessionUploadTask *uploadTask = [defaultSession uploadTaskWithRequest:someRequest fromData:body];
    [uploadTask resume];
}  

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = NO;

    if (self.uploadResponseData)
    {
        NSDictionary *d = [NSJSONSerialization JSONObjectWithData:self.uploadResponseData options:kNilOptions error:nil];
        NSLog(@"Dict: %@",d);
    }

    if ([task isKindOfClass:[NSURLSessionDownloadTask class]])
    {
        // Not called
    }
    else if ([task isKindOfClass:[NSURLSessionUploadTask class]])
    {
        // Not called
    }
}

- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
    if (!self.uploadResponseData)
    {
        self.uploadResponseData = [NSMutableData dataWithData:data];
    }
    else
    {
        [self.uploadResponseData appendData:data];
    }
}
klcjr89
  • 5,862
  • 10
  • 58
  • 91
  • For starters, what kind of class *is* your task? In the above code it would be perfectly valid for your "Not called" sections not to be invoked if it were an NSURLDataTask. – Matt Gibson Jul 01 '14 at 07:27
  • `NSURLSessionDownload` & upload tasks are subclasses of `NSURLSessionDataTask`, however `NSURLSessionDataTask` is a subclass of `NSURLSessionTask`, so I don't see why this isn't working. – klcjr89 Jul 01 '14 at 14:01
  • Am I missing something? I was asking what kind of class the task you're expecting is, because if it's an NSURLDataTask, that means it's neither an NSURLSessionUploadTask, nor an NSURLSessionDownloadTask, which would explain why your code's not working. And I think that's what you just said, too. NSURLSessionDataTask being a subclass of NSURLSessionTask doesn't have anything to do with my point, as far as I can see... – Matt Gibson Jul 01 '14 at 14:04
  • So how do you call isKindOfClass isKindOfClass twice to get the superclass? – klcjr89 Jul 01 '14 at 18:18
  • Can I ask again: what kind of class is the task you're trying to detect? – Matt Gibson Jul 01 '14 at 21:29
  • Shows above in my code. And why the down vote – klcjr89 Jul 01 '14 at 22:10
  • No, I mean: what kind of task did you add to the session in the first place, to cause the above code to run? Can we see your code that adds the task(s) to the session? – Matt Gibson Jul 02 '14 at 07:16
  • Updated my question with the corresponding upload code – klcjr89 Jul 02 '14 at 14:59
  • I've just tested this, and if I add an NSURLSessionUploadTask to my session and kick it off, then in my didCompleteWithError, I can successfully detect it with `if ([task isKindOfClass:[NSURLSessionUploadTask class]])`... Still digging. – Matt Gibson Jul 02 '14 at 16:37

2 Answers2

4

My experience with this has been in the context of app-in-the-background NSURLSessionTasks. These get serialized to disk, there's a deamon involved, and my experience is that any class-based finagling didn't work too well in that context.

Particularly, I was trying to subclass NSURLSessionTask, but what came back in the -didComplete:... call was not an instance of that subclass.

I've come to think of NSURLSessionTask as a facade, or part of a "class cluster", and tried to be more careful about it.

If you need to mark a task as a particular type, you store whatever you like in the .description. I can confirm that info survives background serialization nicely.

Clay Bridges
  • 11,602
  • 10
  • 68
  • 118
1

I can't reproduce the issue from the code you've posted. I made a minimal example from your code, just creating a single-view application from the standard Xcode template, then using this as the view controller:

ViewController.h:

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController <NSURLSessionDelegate, NSURLSessionTaskDelegate>

@end

ViewController.m:

#import "ViewController.h"

@interface ViewController ()


@end

@implementation ViewController

 1. (void)viewDidLoad {
    [super viewDidLoad];
    [self uploadIt];
}

 2. (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

 3. (void)uploadIt
{
    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration ephemeralSessionConfiguration];
    defaultConfigObject.timeoutIntervalForResource = 15.0;
    defaultConfigObject.requestCachePolicy = NSURLRequestReloadIgnoringLocalAndRemoteCacheData;

    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration:defaultConfigObject delegate:self delegateQueue:[NSOperationQueue mainQueue]];

    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

    NSURLRequest* someRequest = [NSURLRequest requestWithURL: [NSURL URLWithString:@"http://example.com"]];
    NSData* body = [@"Fake body" dataUsingEncoding:NSUTF8StringEncoding];

    NSURLSessionUploadTask *uploadTask = [defaultSession uploadTaskWithRequest:someRequest fromData:body];
    [uploadTask resume];
}

-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error {
    NSLog(@"Completed.");

    if ([task isKindOfClass:[NSURLSessionDownloadTask class]])
    {
        NSLog(@"The task was a download task");
    }
    else if ([task isKindOfClass:[NSURLSessionUploadTask class]])
    {
        NSLog(@"The task was an upload task");
    }
}
@end

The result was the following:

2014-07-02 17:57:28.002 24500545_nsurlsession_classes[22470:1250475] Completed. 2014-07-02 17:57:48.631 24500545_nsurlsession_classes[22470:1250475] The task was an upload task

(Are you certain you're logging correctly? What do you see if you set a breakpoint in your delegate method and step through the code? What does p task tell you in lldb?)

Matt Gibson
  • 37,886
  • 9
  • 99
  • 128
  • Hmm of course it works if I make a barebones project. So weird! – klcjr89 Jul 02 '14 at 18:41
  • Actually I'm still having trouble with it. If I initiate an NSURLSessionUploadTask, then the if statement for `([task isKindOfClass:[NSURLSessionDownloadTask class]])` still gets called. Weird – klcjr89 Jul 02 '14 at 19:07
  • Is your code the same as in your original post, or has it changed? (If it's the same, and there's nothing in the "if" statement, how are you checking if it's executed? Wondering if you're seeing some kind of strange result due to optimisation, or something...) – Matt Gibson Jul 02 '14 at 20:01