How to Make Web Service Call Without Making the GUI Unresponsive - iphone

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.

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

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.

Related

what is synchronous and asynchronous in iphone and iPad?

What is synchronous and asynchronous in ios ? I am new in objective c. Which one i should use in my code while i am getting data from server. So please help me.
Thanks in advance.
You should always use asynchronous loading of network requests.
Asynchronous never block the main thread waiting for a network response.
Asynchronous can be either synchronous on a separate thread, or scheduled in the run loop of any thread.
Synchronous blocks main thread until they complete request.
For Demo code or turorial have a look into this link Asynchronous web service client using NSURLConnection and SBJSON
The majority of the time you will go for asynchronous calls for that kind of operations, otherwise you're UI will block because you are using the main thread.
Synchronous, as the name suggests the action will happen in synchronous with the run loop of your application.
To understand it better, say you have to display some data in UITableview after fetching the data from server.Imagine that the request and response from server takes like 3 seconds. When you are fetching this data synchronously from the server, your app will freeze for like 3 seconds between loading tableview and loading the data contents into that tableview
Now if you are sending your request asynchronously, your app won't freeze but it will load the tableview and tableview contents before the server can respond. In other words, your app won't wait for the 3 second of server response time.You have to take necessary delegate actions or blocks actions to check the response and reload the tabledata so that the server response is displayed in tableview.
Which method is better is pure choice what the developer wants and their app should behave but Apple documentation recommends if you are using synchronous calls do not initiate the call from current run loop.
Using asynchronous all threads are execute the operations parallel. So, Never block the main thread waiting for a network response.
Using synchronous all threads are execute the operations one by one. so, should wait until the other thread task done.
Hope It will be suitable.
Quick note based on other answers: dispatch_sync will not block the main thread unless you dispatch to the main thread.
Example:
// Block main thread because the main queue is on it.
dispatch_sync(dispatch_get_main_queue(), ^{ /*do stuff*/ });
// Block background thread.
dispatch_sync(my_work_queue, ^{ /*do stuff*/ });
A Synchronous call(blocking) is one that has to be completed before subsequent calls can be run in the same queue. It is given all of the processor time for that queue until it is complete. This makes it block the queue.
Asynchronous calls can be started in a queue, and then left running on another thread(processor time schedule), owned by that queue, while other calls are started with other threads.
It is very important to use dispatch_async for web calls because it may take time to get a result back and you want other tasks to be able to start in the queue and use it's threads. A common practice is to do web work, like downloading a file, on a custom background queue and then dispatch to the main queue when it is complete, to update the user.
There is more to this and you can read about dispatch queues from Apple, here.

How to wait for a certain status of a NSURLConnection

Sorry to bother with yet another NSURLConnection question, adding to the over one thousand already here.
The scenario is as follows. In an iPhone app using dynamically loaded augmented reality features, the user is prompted to download new AR models as these are made available. The models can be several MB large, so the user should be given an indication of the total size of all models to be downloaded before deciding to do so.
To find out how large each file is I want to use an asynchronous NSURLConnection but then to stop the download once I have got the response ([NSURLResponse expectedContentLength]). I can do this in the delegate's connection:didReceiveResponse: method.
My question is, how can I wait until this condition arises? How can I setup the NSURLConnection, let it start asynchronously and then wait until the connection:didReceiveResponse: method is called? I have tried using a NSCondition, letting this wait after setting up the NSURLConnection and in the connection:didReceiveResponse: method signalling the condition. But all this did was to freeze the main thread. Any ideas?
Maybe you could send a HEAD request instead of GET. This may depend on your server set up, but that should get you just the headers, including Content-Length. You ought to be able to use a NSMutableURLRequest so you can change the request method, and then read expectedContentLength on the response as usual.

ASIHTTPRequest multiple Async request issue

When I put an asynchronous ASIHTTPRequest to work, called Request1, when it finishes it calls the - (void)requestFinished:(ASIFormDataRequest *)request2 which is the wrong thread. How does that happen, and more importantly, how do i avoid it?
ASIHTTPRequest should always call it's request finished / error methods on the main thread.
If you want to then go back into another thread then it's up to you to do that (i.e. performSelectorInBackground:, NSOperationQueue etc).

Does NSURLConnection block the main thread?

I'm using NSURLConnection in an iPhone application and the interface seems to slow down after sending initWithRequest: to my NSURLConnection instance. I'm not sure if this is occurring because my processing code is taking a long time to handle the response, or if it's because NSURLConnection is blocking the main thread.
Can anyone confirm that NSURLConnection will create the connection and wait for data on a separate thread, and then call its delegate methods on the main thread?
Thanks!
NSURLConnection supports two modes of operation: asynchronous and synchronous. Neither uses separate threads at all. They both use just one thread, that being whatever thread you run them in.
In synchronous mode, NSURLConnection will block whatever thread you run it in. Asynchronous mode uses the run loop to behave (from the developer's perspective) similarly to a background thread but with lower overhead and without any thread-safety issues. If using asynchronous mode, you want to run it in the main thread. It won't block anything.
If your interface is slowing down, that is not consistent with using NSURLConnection synchronously, which would instead cause your interface to stop completely until the request is complete.
If you follow apples example on NSURLConnection the call will be handled in a different thread than the main thread.

ASIHTTPRequest synchronously

I have an iPhone app which uses ASIHTTPRequest to communicate to a REST service on my server. When I'm running on the simulator, it works just fine, but when I get onto the phone itself, I get weird behavior.
The very first time I click the button that initiates the request, I get the results back immediately, and all is fine. From that point on, when I click the button to initiate the connection it takes about 2-3 minutes to connect. It almost seems like the ASIHTTPRequest that I kicked off first (and from which I've already received the correct results) has not completed. Is there some sort of magic I need to use to terminate the original request before starting the next one? I assumed that since the -start method returned, and I have results from the server that the original request was completed and I could start another.
Any ideas?
Thanks
--Steve
Steve - What you've described is a common problem that will occur if the requests are attempting to keep a persistent connection. Try this out:
[request setShouldAttemptPersistentConnection:NO];
You're not suppose to call the -start method, it belongs to the NSOperation. The ASIHTTPRequest interface is either -startSynchronous or -startAsynchronous.
However, it's highly recommend to use the asynchronous call otherwise, your main thread (ie., UI) will be blocked.
From the ASIHTTPRequest documentation[1]
In general, you should use
asynchronous requests in preference to
synchronous requests. When you use
ASIHTTPRequest synchronously from the
main thread, your application's user
interface will lock up and become
unusable for the duration of the
request. Synchronous requests are only
really suitable for software without a
UI (like a script that runs from the
terminal), or if you are running the
request from a separate thread that
you maintain (perhaps from inside your
own NSOperation, for example).
[1] http://allseeing-i.com/ASIHTTPRequest/How-to-use