I set up a UITableView that is supposed to display some information once certain data is loaded from a website. In order for the UI to update and the data to finish loading I used the method:
performSelectorOnMainThread:@selector(getBooks) withObject:nil waitUntilDone:YES
-(void)getBooks{
NSMutableString *theURL = [[NSMutableString alloc] initWithString:@"theURL"];
[theURL appendFormat:@"&UserID=%@", _appDel.userID];
NSLog(@"%@\n", theURL);
NSURLRequest *theRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:theURL]
cachePolicy:NSURLRequestUseProtocolCachePolicy
timeoutInterval:10.0];
NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
if (theConnection) {
receivedData = [NSMutableData data];
} else {
// Inform the user that the connection failed.
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"An Error Occured" message:@"Couldn't make a connection to the server. Please make sure your internet connection is on." delegate:self cancelButtonTitle:@"Ok" otherButtonTitles: nil];
[alert show];
}
}
However, when I run this the program continues executing although I set waitUntilDone to YES. I was under the impression that waitUntilDone would wait on the selector until it has finished executing. Can anyone explain what the possible issue could be? Thanks for any help.
If you look at the Apple docs, they say:
So, if you call this method from the main thread, then it will be executed immediately.
But, there’s really no point in doing so. If you are on the main thread, and wish to execute
getBookson the main thread, then just do this:If you show us what you’re actually doing inside
getBooks, we might be able to help more. For example, ifgetBooksis making a remote HTTP request, to get online book data, then you don’t want to useperformSelectorOnMainThread:at all. You want to run that on a background thread, and then only call back the main thread to update your UI, once the network request has completed.Update:
There’s many ways to retrieve web content. If you are going to use the
NSURLRequestdirectly, as you are, then you should make sure this class implements theNSURLConnectionDelegateprotocol:and then implement its methods per the Apple example
A note: the code above was written before ARC was introduced. If your project uses ARC, you’ll need to remove all those lines with
releasecalls. It is advisable, however, to make sure yourreceivedDatais properly retained, since you’ll be using it across multiple calls.Another note:
NSURLConnectioncan be used in multiple ways. It can be used synchronously, or asynchronously. And, you can always decide which thread to start it on. If you keep this:then the connection will be started on the main thread. But, it will still be an asynchronous operation. In other words, it won’t block
viewDidLoaduntil the network request finishes. However, if the user is going to be doing anything significant with the UI while the download happens (like scrolling), then you may find your UI becomes less responsive. If that’s the case, you may either want to do this, or force the network operation onto a background thread. To do that, start it with:Then, the only problem with my above
NSURLConnectionDelegatecode is that the background thread will not live long enough to deliver the response via your delegate callbacks. To keep it alive,And then you must add this call to the end of both
connectionDidFinishLoadingandconnection:didFailWithErrorto clean up this background run loop:Again, old code, so use
for ARC.