4
votes

I'm trying to download a 94KB image file from my server. I've tried two ways to do this: using NSURLSession dataTaskWithURL and NSData dataWithContentsOfURL.

NSURLSession:

Globals *global = [Globals getInstance];

// GET request to /mobile/image
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/mobile/image/%@", [global rootUrl], self.photoId]];
NSURLSession * session = [global session];
NSDate *start = [NSDate date];
[[session dataTaskWithURL:url completionHandler:^(NSData *imgData, NSURLResponse *response, NSError *error) {
    NSLog(@"Time taken: %f", [[NSDate date] timeIntervalSinceDate:start]);
    NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *) response;
    if ([httpResponse statusCode] != 200) {
        // error
    } else {
        dispatch_async(dispatch_get_main_queue(), ^ {
            UIImage *image = [UIImage imageWithData:imgData];

            CGFloat width = self.photoImageView.frame.size.width;
            CGFloat height = image.size.height / image.size.width * width;
            self.imageHeight.constant = height;

            self.photoImageView.image = image;
        });
    }
}] resume];

NSData:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^ {
    Globals *global = [Globals getInstance];

    // GET request to /mobile/image
    NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:@"%@/mobile/image/%@", [global rootUrl], self.photoId]];
    NSDate *start = [NSDate date];
    NSData *imgData = [NSData dataWithContentsOfURL:url];
    NSLog(@"Time taken: %f", [[NSDate date] timeIntervalSinceDate:start]);
    UIImage *image = [UIImage imageWithData:imgData];

    CGFloat width = self.photoImageView.frame.size.width;
    CGFloat height = image.size.height / image.size.width * width;

    dispatch_async(dispatch_get_main_queue(), ^{
        self.imageHeight.constant = height;
        self.photoImageView.image = image;
    });
});

Here is the output for my NSLog for how long they took to complete:

NSURLSession:

Time taken: 6.585221
Time taken: 3.619189
Time taken: 4.408179
Time taken: 9.931350
Time taken: 3.689192

NSData:

Time taken: 0.157747
Time taken: 0.135785
Time taken: 0.576947
Time taken: 0.462661
Time taken: 0.337266

Taking 3~10 seconds to download a simple <100KB image file is unacceptable, so I'm currently just sticking with NSData, but I need to use NSURLSession later for another similar image download task because I need login sessions.

I'm wondering if I've accidentally discovered a weird bug with NSURLSession, if it's just supposed to be much slower because it has all the overhead of sessions, or if I'm doing something wrong.

Edit:

I figured it out, thanks for all your help!

I created a whole new project with all the connections of this one, and it performed fine.

Problem: The previous VC that before this was calling dataTask multiple times. I was completely baffled why that would affect this VC. Turned out that the class was called ViewController (default name), and this VC was inheriting ViewController instead of UIViewController.

Therefore, calling [super viewDidLoad] from the viewDidLoad of this ViewController was actually calling the previous VC and running all those dataTasks all over again.

When in doubt, check all the other connections in the session.

1
It might be worthwhile to fool around with the session's configuration (NSURLSessionConfiguration. I'd start with caching) to see if something has a big impact on time.danh
I didn't bother to cache because I didn't cache for NSData either. (Both are ran completely clean.) As for my session configuration: NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration]; NSURLSession *session = [NSURLSession sessionWithConfiguration:config]; It's pretty much the default, and I haven't changed any config anywhere else.pchiang
When I view the network usage for NSURLSession, it seems to go down to zero KB/s in the middle of a download task, and then go back up a couple seconds later, repeat until complete. Does it maybe have something to do with it being ran in the background?pchiang
The problem does not rest in the code above. Nor does the problem rest in NSURLSession, which is a very robust piece of networking code. The provided code is not enough to reproduce the problem you describe. Perhaps you can construct the simplest possible example that manifests the problem you describe, and share that with us?Rob
@pchiang You should go ahead and post your conclusion as an "answer" rather than editing the question with your findings. See Can I answer my own question?Rob

1 Answers

3
votes

You're having a threading problem. Do not run that code (the NSURLSession code) in a background thread! Run it on the main thread. Don't worry, this won't block the main thread; the whole point of NSURLSession is that it operates asynchronously so that you don't have to.