NSURLConnection, NSOperation and NSRunLoop confusion over threading

痞子三分冷 提交于 2019-12-23 06:55:35

问题


I got confused while working with NSURLConnection and NSRunLoop. I’m trying to download a large file using NSURLConnection but it’s NOT working (Not even calling a single delegate method) as expected.

    NSURL *url = [NSURL URLWithString:@"http://127.0.0.1:8080/"];
    NSMutableURLRequest *request = [[[NSMutableURLRequest alloc] initWithURL:url] autorelease];
    [request setHTTPBody:[@"Request Body Data" dataUsingEncoding:NSUTF8StringEncoding]];
    [request setHTTPMethod:@"POST"];

Running on main Thread.

Only working for small size of file. It didn’t work when I try to download an 18MB file.

  1. It didn't work for large image files.

    [NSURLConnection connectionWithRequest:request delegate:self];
    
  2. It didn't work for large image file, tried with 18MB.

    NSURLConnection *con = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
    [con setDelegateQueue:[NSOperationQueue currentQueue]];
    [con start];
    
  3. It didn't work for large image file, tried with 18MB.

    NSURLConnection *con = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
    [con scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSDefaultRunLoopMode]; // Or NSRunLoopCommonModes
    [con start];
    
  4. It didn't work for large image file, tried with 18MB.

    NSURLConnection *con = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO];
    NSRunLoop *loop = [NSRunLoop currentRunLoop];
    [con scheduleInRunLoop:loop forMode:NSRunLoopCommonModes];
    [con start];
    [loop run];
    
  5. It didn't work for large image file, tried with 18MB.

    NSHTTPURLResponse *res = nil;
    NSError *err = nil;
    NSData *data = [NSURLConnection sendSynchronousRequest:request returningResponse:&res error:&err];
    NSLog(@"Res Code: %d, DataLen: %d", res.statusCode, data.length);
    
  6. It WORKED for large image as well

    [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
        NSHTTPURLResponse *res = (NSHTTPURLResponse*)response;
        NSString *imagePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"/myImage.jpg"];
        NSLog(@"Res Code: %d, DataLen: %d, Path: %@", res.statusCode, data.length, imagePath);
        [data writeToFile:imagePath atomically:YES];
    }];
    

Running on NSOperation (I have attempted same above code in NSOperation's subclass, I have uploaded the code on github. Please find the link below.)

  1. Nothing worked (None of the delegate method get called.)
  2. It WORKED for all.
  3. It didn’t work for large file.
  4. It WORKED for all. (It worked for NSDefaultRunLoopMode mode as well, where apple document says this “The mode to deal with input sources other than NSConnection objects.”).
  5. It WORKED for all.
  6. It WORKED for all.

I just want to understand the basic logic behind NSRunLoop, when we use it with NSURLConnection object. How NSRunLoop works behind the scene? How does it work with NSURLConnections? What happens when we call any asynchronous request through NSURLConnection on main thread or any secondary thread (created by NSOperation)?

Sample Code on GitHub

I have read several blogs and apple documents related to NSRunLoop but still confused, so i have written a doc over my understanding about the same. NSRunLoop understanding Doc.

Many thanks in advance!


回答1:


Confusion is good, it's a signal that you are missing answers and probably even questions. As far as I can see, the missing question here is: do we really need NSOperation and NSRunLoop? NSURLConnection sendAsynchronousRequest: and sendSynchronousRequest: already schedule operations in runloops -- adding NSOperation and NSRunLoop doesn't help and probably hinders. So, concentrate on the methods that you really need (sendAsynchronousRequest: or sendSynchronousRequest:) and make full use of them. Take this code:

[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue currentQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
    NSHTTPURLResponse *res = (NSHTTPURLResponse*)response;
    NSString *imagePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"/myImage.jpg"];
    NSLog(@"Res Code: %d, DataLen: %d, Path: %@", res.statusCode, data.length, imagePath);
    [data writeToFile:imagePath atomically:YES];
}];

You do cast NSURLResponse to NSHTTPURLResponse, presumably to read out the status code, but instead you forge ahead and write the data object to file anyway. If the status code is anything but 200, there is no valid data object to write to file. The status code may be 206, in which case you will need to append the incoming data to an already existing file, or create one if it doesn't exist and store a reference to it, etc.



来源:https://stackoverflow.com/questions/24895099/nsurlconnection-nsoperation-and-nsrunloop-confusion-over-threading

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!