user3818304
user3818304

Reputation: 11

How can I get NSURLSession to process completionHandler when running as a command-line tool

I am somewhat new to Objective-C. I have some PERL scripts that download files from a site that requires client certificate authentication. I would like to port those scripts from PERL to Objective-C command line tools that I can then run from Terminal. Based on my research I have concluded that NSURLSession should work for what I need to do. However, I have been unable to get NSURLSession to work in my command line tool. It seems to build fine with no errors, but does not return anything from the completionHandler. Further, I have put this same code into a Mac OS X App tool and it seems to work fine.

Here is my main.m file:

#import <Foundation/Foundation.h>
#import "RBC_ConnectDelegate.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {

        // insert code here...

        NSURL *myURL =[NSURL URLWithString:@"http://google.com"];

        //[[[RBC_Connect alloc] init] connectGetURLSynch];
        RBC_ConnectDelegate *myConnect = [[RBC_ConnectDelegate alloc] init];
        [myConnect GetURL2: myURL];


    }
    return 0;
}

Here is my Implementation File:

#import <Foundation/Foundation.h>


@interface RBC_ConnectDelegate : NSObject 

- (void)GetURL2:(NSURL *)myURL;

@property(nonatomic,assign) NSMutableData *receivedData;
//<==== note use assign, not retain
//do not release receivedData in a the dealloc method!

@end

And here is my implementation file:

#import "RBC_ConnectDelegate.h"

@implementation RBC_ConnectDelegate

- (void)GetURL2:(NSURL *)myURL2{
    //create semaphore
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
    // Create the request.
    NSLog(@"Creating Request");
    NSURLRequest *theRequest =
    [NSURLRequest requestWithURL:myURL2
                     cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
                 timeoutInterval:10.0];
     NSLog(@"Creating Session");
    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
    NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate: nil delegateQueue: [NSOperationQueue mainQueue]];
     NSLog(@"Initializing Data Task");
    NSURLSessionDataTask * dataTask = [defaultSession dataTaskWithRequest:theRequest
                            completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {

                                NSLog(@"CompletionHandler");

                                if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
                                    NSInteger myStatusCode = [(NSHTTPURLResponse *) response statusCode];
                                    NSLog(@"Status Code: %ld", (long)myStatusCode);

                                }



                                if(error == nil)
                                {
                                    NSString * text = [[NSString alloc] initWithData: data encoding: NSUTF8StringEncoding];
                                    NSLog(@"Data = %@",text);
                                }
                                else
                                {
                                NSLog(@"Error");
                                }
            dispatch_semaphore_signal(semaphore);
                                                        }];

    NSLog(@"Resuming Data Task");
    [dataTask resume];
}
@end

As you can see, I am trying to get something very simple working here first, with the idea that I can then build on it. Everything I have looked at suggests this may be related to the fact that NSURLSession runs asynchronously but I have been unable to find a solution that speaks specifically to how to address this issue when building a command-line tool. Any direction anyone can provide would be appreciated.

cheers,

Upvotes: 1

Views: 673

Answers (1)

tsnorri
tsnorri

Reputation: 2097

NSOperationQueue's reference says that for +mainQueue, the main thread's run loop controls the execution of operations, so you need a run loop. Add this to the end of your main:

while (1)
{
    SInt32 res = 0;
    @autoreleasepool
    {
        res = CFRunLoopRunInMode(kCFRunLoopDefaultMode, DBL_MAX, false);
    }

    if (kCFRunLoopRunStopped == res || kCFRunLoopRunFinished == res)
        break;
}

To call -GetURL2:, use -[NSOperationQueue addOperation:] or dispatch_async. You can stop execution with CFRunLoopStop. I tested with GCD instead of NSOperations but this should work anyway.

Also, you need to call dispatch_semaphore_wait if you want to synchronize after the URL session is complete.

Upvotes: 1

Related Questions