0

I'm having an issue with an objective-C uploader class that will not upload (fail / success delegate not called and the server shows no incoming request) unless I have a spin loop. It works perfectly with a spin loop.

I'm new to objective-C, The setup is as follows: Main app instantiates a C++ class (cppClass) that runs a static function (cppFuncA) in a separate pThread.

Static function (cppFuncA) instantiates an objective-C class/object (UploadFunc) which takes some data and uploads it.

CppClass {
    static void cppFuncA (...);
} 

cppFuncA(...) {
    UploadFunc* uploader = [[[UploadFunc alloc] retain] init];
    while (condition) {
        ...
        [uploader uploadData:(NSData*)data];
    }
    [uploader release]
}

Uploader.h

@interface UploadFunc : NSObject
{
    bool conditional;
}
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error;
- (void)connectionDidFinishLoading:(NSURLConnection *)connection;
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;
- (void) uploadData:(NSData*)data;
@end

Uploader.mm

@implementation UploadFeedback
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    conditional = false;
    [connection release];
    NSLog(@"Connection failed! Error - %@ %@",
          [error localizedDescription],
          [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    conditional = false;
    NSLog(@"Succeeded! Received %d bytes of data",0);
    [connection release];
}
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
    NSLog(@"Response=%@", response);
}

-(void) uploadData:(NSData*)data
{
    …
    NSMutableURLRequest *theRequest=[NSMutableURLRequest requestWithURL:theURL];
    … construct request …

    NSURLConnection* theConnection = [[NSURLConnection alloc] initWithRequest:theRequest delegate:self];

    // Only works if I have this following spin loop
    conditional = true;
    while(conditional) {     
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }
    if (!theConnection) std::cerr << "Connection to feedback failed\n";
}

The last function "-(void) uploadData:(NSData*)data" is where I am having my issue. It will not work without the spin loop. Any ideas on what is going on?

I added retain to the NSURLRequest and NSURLConnection so I do not think its a race condition where the request is not being copied.

EDIT: I feel like these might be a similar issues: NSURLConnection - how to wait for completion and Asynchronous request to the server from background thread however my object (UploadFunc) still exists even after the function finishes and goes out of scope...

Community
  • 1
  • 1
encore2097
  • 481
  • 3
  • 8
  • 18

1 Answers1

1

Don't run your run loop in the default mode. The framework can put other run loop sources into the default mode and they will fire when you mean to be just processing your NSURLConnection. Admittedly, it should be uncommon for the frameworks to schedule other sources on the run loop of a background thread, but you can't be sure.

Running the run loop should not busy-loop. You shouldn't be spiking the CPU usage unless data is coming in faster than you can handle it. The fact that it seems to be busy-looping is what makes me suspect there's another run loop source scheduled in the default mode.

Schedule the NSURLConnection in a private run loop mode (just any arbitrary string that's unique to your app) and then run the run loop in that mode. You can init the NSURLConnection with -initWithRequest:delegate:startImmediately:, passing NO for the last argument to avoid scheduling in the default mode. Then use -scheduleInRunLoop:forMode: to schedule it in your private mode.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154