In my app when the user presses a button I start a HTTP asynchronous request (using [NSURLConnection sendAsynchronousRequest...]
) and change the text of UILabel
in the completionHandler
block. This change, however, does not take place when the request is concluded and instead happens around 2-3 seconds later. Below is a code snippet that results in this behavior.
- (IBAction)requestStuff:(id)sender
{
NSURL *url = [NSURL URLWithString:@"http://stackoverflow.com/"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:
^(NSURLResponse *response, NSData *data, NSError *error)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
exampleLabel.text = [NSString stringWithFormat:@"%d", httpResponse.statusCode];
}];
}
A similar behavior happens when I attempt to create an UIAlertView
inside the completionHandler
.
- (IBAction)requestStuff:(id)sender
{
NSURL *url = [NSURL URLWithString:@"http://stackoverflow.com/"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:
^(NSURLResponse *response, NSData *data, NSError *error)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
if ([httpResponse statusCode] == 200) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"It worked!"
message:nil
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
}];
}
A small difference, though, is that the screen dims when [alert show]
is executed. The alert itself only appears 2-3 seconds later like in the previous scenario.
I'm guessing this is related to how the UI is handled by the app's threads, but I'm not sure. Any guidance on why the delay happens will be greatly appreciated.
According to The Apple Docs.
Threads and Your User Interface
If your application has a graphical user interface, it is recommended that you receive user-related events and initiate interface updates from your application’s main thread. This approach helps avoid synchronization issues associated with handling user events and drawing window content. Some frameworks, such as Cocoa, generally require this behavior, but even for those that do not, keeping this behavior on the main thread has the advantage of simplifying the logic for managing your user interface.
Calling your UI updates on the main thread would solve this problem. Surround your UI code with a call to the main thread (below).
dispatch_async(dispatch_get_main_queue(), ^{
exampleLabel.text = [NSString stringWithFormat:@"%d", httpResponse.statusCode];
});
There are other ways to do calls on the main thread, but using the simpler GCD commands would do the job. Again, see the Threaded Programming Guide for more info.
This could happen because all UI stuff should be called in a main queue. Try this:
- (IBAction)requestStuff:(id)sender
{
NSURL *url = [NSURL URLWithString:@"http://stackoverflow.com/"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[[NSOperationQueue alloc] init] autorelease];
[NSURLConnection sendAsynchronousRequest:request queue:queue completionHandler:
^(NSURLResponse *response, NSData *data, NSError *error)
{
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
dispatch_async(dispatch_get_main_queue(), ^{
exampleLabel.text = [NSString stringWithFormat:@"%d", httpResponse.statusCode];
});
}];
}
You can try to create a method that sets the text, and inside the block you call:
[self performSelectorOnMainThread:@selector(mySelector) withObject:nil waitUntilDone:NO];
The selector will call and executed on main thread. Hope this help....
来源:https://stackoverflow.com/questions/11386403/delay-when-updating-view-in-the-completionhandler-of-an-async-http-request