kernix
kernix

Reputation: 8490

How to Make Web Service Call Without Making the GUI Unresponsive

I have a UISearchBar and UISearchDisplayController. When the user writes text in it inside searchBar:textDidChange: I make a web-service call to filter my TableView. The problem is that the GUI get unresponsive until I get the result from the web-service. I've tried to solve it using [self performSelector:@selector(callWebService:) withObject:searchText];, but it's still unresponsive.

EDIT: Following Flink advice, I changed performSelector to performSelectorInBackground, but now the tableView doesn't filter correctly, it only show 'No Results'. even tableView:numberOfRowsInSection: isn't get called.

EDIT Again: The reason I got 'No Results' was due to not calling reloadData on the correct tableView. UISearchDisplayController has a property named searchResultsTableView. So in the end what I used was [self.searchDisplayController.searchResultsTableView performSelectorOnMainThread:@selector(reloadData) withObject:nil waitUntilDone:false]; and now it works fine.

It should be noted that although I chose the performSelectorInBackground, I probably should have tried to use sendAsynchronousRequest method on NSURLConnection - See AliSoftware's answer.

Upvotes: 1

Views: 1122

Answers (2)

AliSoftware
AliSoftware

Reputation: 32681

You should avoid creating a background queue or thread to perform your network request(which is what performSelectorInBackground: does) as this creates a worker thread just for this which is not as efficient as scheduling the request on the NSRunLoop.

Dedication a thread will make the processor activate the thread regularly to check if there are some data, and creating a thread for that is quite overkill. Scheduling the request on the run loop (as a run loop source) will use network interruptions to signal incoming data from the socket and thus will only be activated when there is actual data available.

To do this, simply use the asynchronous methods provided by NSURLConnection.

  • One solution is to use the delegate approach provided by NSURLConnection (this is the old way to do it, the only way that was available in the NSURLConnection API back in iOs3)
  • Another more modern solution is to use the block API provided by NSURLConnection which is easier to use and code.

    [NSURLConnection sendAsynchronousRequest:request
                                       queue:[NSOperationQueue mainQueue]
                           completionHandler:^(NSURLResponse* response, NSData* receivedData, NSError* error)
     {
       // Your code to execute when the network request has completed
       // and returned a response (or timed out or encountered an error)
       // This code will execute asynchronously only once the whole data is available
       // (the rest of the code in the main thread won't be blocked waiting for it)
     }];
    // After this line of code, the request is executed in the background (scheduled on the run loop)
    // and the rest of the code will continue: the main thread will not be frozen during the request.
    

Read more in the URL Loading System Programming Guide and in the NSURLConnection class reference.

Upvotes: 1

Shmidt
Shmidt

Reputation: 16664

You need to make your web call async.

http://www.raywenderlich.com/4295/multithreading-and-grand-central-dispatch-on-ios-for-beginners-tutorial

In your case, you can change performSelector to performSelectorInBackground

Upvotes: 1

Related Questions