Asynchronous request to the server from background thread

萝らか妹 提交于 2019-11-27 16:58:21

Yes, the thread is exiting. You can see this by adding:

-(void)threadDone:(NSNotification*)arg
{
    NSLog(@"Thread exiting");
}

[[NSNotificationCenter defaultCenter] addObserver:self
                                         selector:@selector(threadDone:)
                                             name:NSThreadWillExitNotification
                                           object:nil];

You can keep the thread from exiting with:

-(void) downloadImage
{
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
    [self downloadImage:urlString];

    CFRunLoopRun(); // Avoid thread exiting
    [pool release];
}

However, this means the thread will never exit. So you need to stop it when you're done.

- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
    CFRunLoopStop(CFRunLoopGetCurrent());
}

- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
    CFRunLoopStop(CFRunLoopGetCurrent());
}

Learn more about Run Loops in the Threading Guide and RunLoop Reference.

You can start the connection on a background thread but you have to ensure the delegate methods are called on main thread. This cannot be done with

[[NSURLConnection alloc] initWithRequest:urlRequest 
                                delegate:self];

since it starts immediately.

Do this to configure the delegate queue and it works even on secondary threads:

NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:urlRequest 
                                                              delegate:self 
                                                      startImmediately:NO];
[connection setDelegateQueue:[NSOperationQueue mainQueue]];
[connection start];

NSURLRequests are completely asynchronous anyway. If you need to make an NSURLRequest from a thread other than the main thread, I think the best way to do this is just make the NSURLRequest from the main thread.

// Code running on _not the main thread_:
[self performSelectorOnMainThread:@selector( SomeSelectorThatMakesNSURLRequest ) 
      withObject:nil
      waitUntilDone:FALSE] ; // DON'T block this thread until the selector completes.

All this does is shoot off the HTTP request from the main thread (so that it actually works and doesn't mysteriously disappear). The HTTP response will come back into the callbacks as usual.

If you want to do this with GCD, you can just go

// From NOT the main thread:
dispatch_async( dispatch_get_main_queue(), ^{ //
  // Perform your HTTP request (this runs on the main thread)
} ) ;

The MAIN_QUEUE runs on the main thread.

So the first line of my HTTP get function looks like:

void Server::get( string queryString, function<void (char*resp, int len) > onSuccess, 
                  function<void (char*resp, int len) > onFail )
{
    if( ![NSThread isMainThread] )
    {
        warning( "You are issuing an HTTP request on NOT the main thread. "
                 "This is a problem because if your thread exits too early, "
                 "I will be terminated and my delegates won't run" ) ;

        // From NOT the main thread:
        dispatch_async( dispatch_get_main_queue(), ^{
          // Perform your HTTP request (this runs on the main thread)
          get( queryString, onSuccess, onFail ) ; // re-issue the same HTTP request, 
          // but on the main thread.
        } ) ;

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