简体   繁体   中英

Async request does not enter completion block

The following code is an attempt to me better understand [NSURLConnection sendAsynchronousRequest:queue:completionHandler] .

There are NSLog statements in the completionHandler block, but when I run this in main.m in XCode from a command line project, it never enters the completionHandler blocks. I've tried using the different queues, mainQueue and currentQueue but neither work.

My hunch is that the queue is being deallocated before the request is completed and that retain cycles are involved.

#import <Foundation/Foundation.h>

int main(int argc, const char * argv[]) {
    @autoreleasepool {
        NSCache *myCache = [[NSCache alloc] init];

        NSArray *images = @[
         @"http://i.stack.imgur.com/E66qr.png",
         @"http://www.tiempoyquimera.com/wp-content/uploads/2010/01/Euro-Trash-Girl-2010.jpg",
         @"http://1.bp.blogspot.com/-Mxd8AB2nbQY/UYCISJiQz3I/AAAAAAAAAH8/Tc43U8aa9dM/s1600/Tarantino10colhans_1460858i.jpg",
         @"https://awestruckwanderer.files.wordpress.com/2014/02/alan-watts.png",
         @"http://www.esalen.org/sites/default/files/photo_images/20120201_DELLIS__MG_9612_711.jpg"];

        for (NSString *image in images){
            NSURL *myURL = [NSURL URLWithString:image];
            NSURLRequest *request = [[NSURLRequest alloc] initWithURL:myURL];

            NSLog(@"Can handle request %@", @([NSURLConnection canHandleRequest:request]));
            NSOperationQueue *queue = [[NSOperationQueue alloc]init];

            [NSURLConnection sendAsynchronousRequest:request
                                               queue:[NSOperationQueue mainQueue]
                                   completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
                                       NSLog(@"In the completion handler");
                                       if (!error)
                                       {
                                           // save data to cache with url as key
                                           NSLog(@"Image Added to Cache");
                                           [myCache setObject:data
                                                       forKey:myURL];
                                       } else
                                       {
                                           NSLog(@"Image Not Added to Cache");
                                       }
                                   }];
        }
    }
    return 0;
}

My hunch is that the queue is being deallocated before the request is completed and that retain cycles are involved

Not quite. Retain cycles are not involved. Persistence is involved. You are doing this in a main function. It exits immediately - the asynchronous stuff (the networking and the subsequent callback) is asynchronous, so it would come later, if we had any persistence. But we don't. main exits, and that means that the whole darned program is torn down, kaboom , before there is any opportunity to do any networking, let alone call back into the completion handler after the networking.

Now contrast this with how things happen in real life. In a real iOS app, main does not exit, because it calls UIApplicationMain , which loops until the app is terminated.

int main(int argc, char *argv[])
{
    @autoreleasepool {
        return UIApplicationMain(argc, argv, nil,
            NSStringFromClass([AppDelegate class]));
    }
}

In that code, UIApplicationMain just keeps running until it is aborted or otherwise terminated. Meanwhile, classes and instance have sprung to life, and they persist, because UIApplicationMain does not stop. For example:

@implementation MyViewController
- (void) someMethod {
    // ...
    [NSURLConnection sendAsynchronousRequest:request
         queue:[NSOperationQueue mainQueue]
         completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
             // ...
    }
}
@end

Now, in one sense, exactly the same thing happens: someMethod exits immediately. But our program overall is still running! UIApplicationMain has a run loop and that run loop is still cycling. Thus, things live on, and so now the asynchronous material can happen - we can network and then call the callback.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM