My app is calling a web service to retrieve some data, and I want to make the experience as best as possible. I figured out that using NSURLConnection it's very hard to give good timely feedback.
Sometimes my iPhone tries to load the data for a minute or two and I see no way of figuring out what is taking so long, or why the download is so troublesome. Then after a few minutes I sometimes end up with an error code.
I'd like to display exactly what is happening. Messages like:
"Establishing internet connection"
"Trying to connect to server"
"Connected..."
"Downloading data..."
"Download complete!"
And when there is trouble like server not reachable or DNS could not be resolved, it would be nice to just try again a few times and not simply quit and throw error.
Are there replacements for NSURLConnection which handle these things more gracefully and give better in-time feedback about what is happening?
I've been a big fan of the AFNetworking library. Very easy to use and wraps all your networking calls in blocks that are very easy to work with.
It is also is kept very current, so you should be safe in getting all the updates it needs as your project progresses and ages.
I think you should be misusing NSURLConnection and NSURLConnectionDelegate, since you can do most of you needs with them.
But, what about MKNetworkKit? I've been using it and it really makes those kind of issues easier to deal with.
Something that can help you achieve what you want. Since ASIHTTPRequest is no longer being supported MKNetworkKit would be your best choice. To check for connectivity, you can always use Reachability.
Related
Been banging our heads on this for two weeks now. Any help will be greatly appreciated.
Problem:
I am using NSURLConnection to fetch JSON data from a RESTfull Web service, the requirement is such that I can't do lazy loading of data. It is one big chunk of data that needs to be processed on the 1st screen of the app every time the logged in user opens the app. I know its not a smart thing to do, but can't help it. The caching is being done in the local Sqlite DB. We are using Async NSURLConnection that is giving us a constant 3-4 sec hit on the performance.
We tried Sync NSURLConnection and figured out the Async NSURLConnection is taking around 3-4 sec extra to process the same request. But Sync NSURLConnection is not reliable at all, it fails to get the complete JSON more than half of the times. And the combination of Sync NSURLConnection with NSOperation will not help.
We tried making the call in a separate app just to observe the performance for that one particular request, and still got the same results.
So, currently we are getting an average execution time of the complete request to be around 6-8 sec. Which we feel I quite high for your first screen of the app. (please let me know if its not much, it feels like bad user experience to me).
Questions:
Isn't NSURLConnection the standard way for doing a request like this?
Is there a better and faster (reliable) way of doing this apart from NSURLConnection?
Can I optimize the performance of NSURLConnection? If yes, please point me to the right direction.
Has anyone tried CFHTTPStream? If yes, then is it better than NSURLConenction in terms of performance?
Thanks
#GoZoner Thanks a ton for the response. We tested in the below three ways
Since it is the 1st screen of the app, so there is no real case of the app doing anything else, still the results were different and a consistent 3-4 sec loss with Async.
We made a raw call in a separate test app, which did nothing but just that one web service call and still the results were same.
We tested on the device and on the simulator. On the device, as expected the results were worse, around 4 secs constant lag in an Async NSURLConnection call.
We were also surprised with the reliability issue as it makes very little sense that a Sync NSURLConnection is unreliable. But after running the tests a zillionth time we realized that it is actually not reliable, not because of something in the NSURLConnection library, but because the 3G or Wi-fi connections are not reliable so the call use to break mostly due to the connection(my assumption). This particular problem is handled beautifully by Async NSURLConnection since it keeps calling and appending data till the data received is complete.(This can sometimes take more than 10-12 attempts to append the data to complete the JSON). Since the Sync NSURLConenction is making only one attempt in getting the data, it fails miserably in the unreliable mobile network connectivity.
#Andrea Thanks for the response :) Will surely give YAJL a spin. But i believe that the problem is more with the connection rather than the parsing of the JSON, I may be wrong. Does YAJL have a reliable connection handling mechanism?
Looking forward to more responses, your suggestions and comments are actually very valuable :)
Thanks
try to use ASIHttpRequest the response time may be faster than the NSURLConnection.
I'm trying to write a method that will operate like this:
NSString *responseData = [myAwesomeWrapper getStringfromURL:#"http://spam.com"];
Behind the scenes, I want to do the request asynchronously (because I need authentication and HTTPS). The problem is obviously that asynchronous requests require delegate callbacks using didReceiveResponse. That prevents me from writing the tidy method I have in mind.
While I understand this approach, I'm sick of the complicating factor it's creating when I need to make several different requests and access the data directly from the same controller. Inventing ways to capture the data without conflicting with existing calls is growing old.
I've read about possibly using NSNotificationCenter to imitate this, but the examples I've read don't reveal an obvious way to make this work.
Is my C# brain asking for too much?
Full disclosure: I'm really new at Objective-C/Cocoa-Touch. Go easy on me. :)
Sounds like a job for ASIHTTPRequest
I am currently trying to build a (simplified) stock app (like the one built-in on the iphone). I setup a simple server with a REST-interface which my app can communicate with.
However I am struggling to find the right/best way to build this kind of (streaming data consumer) client on the iphone.
My best bet at the moment is to use a timer to regularly pull the xml payload from the server (the connection is async but the xml parsing is not therefor the interface is blocked sometimes. I am a bit shy of thread programming since I learned some lessons the hard way on other platforms).
I read about websockets but it is not clear for me if and how they are supported on the iphone.
How would you do it?
Any hint would be appreciated, Thanks.
websockets aren't going to help you -- that's a server-side technology to make a socket-like interface work over HTTP.
If you don't want to block the GUI, you need to use another thread. You are right to be scared of doing this, so share as little as possible (preferably nothing) between the two threads. Use a message passing mechanism to get information from the background thread to the UI thread.
Take a look at ActorKit: http://landonf.bikemonkey.org/code/iphone/ActorKit_Async_Messaging.20081203.html
Take a look at this question.
It talks about asynchronous vs synchronous connections. You will want to use an asynchronous call to get your data so you don't lock up your UI. You could use that in conjunction with a polling timer to get your data from the server.
You can find more info about the NSURLConnection in apple's documentation here
I am a little confused on how to go about and do this....
On each page of my app i connect to PHP file to drag in data from my server. I have about 10 pages. Now if there is no connection to the internet then of course now data can be received.
Often the app crashes and we are putting this down to not having the data due to a change in connection or wifi whatever.
Now i have setup the reachability thing and that works, but i dont know how to link this in with the PHP calls. Should i check the reachability and if no connection then dont run the call. If so, what about all the variables, they will still be null and cause an error then?
I dont really know what is the best solution.
Hope you can help
Alex
Are the php calls just to receive data from a database without using a built in DB framework such as SQLite? If so, I went the same route to avoid the headache at first, but running SQLite in your app is a better solution overall, and reduces multiple dependencies (such as internet connection).
Now if the php calls that give you data back are receiving this information from yet another source and then feeding it into its own DB.....
Should i check the reachability and if no connection then dont run the call
Yes you should. This is done in multiple apps already. What variables would be null in this case? Pop the code that makes the call in an "if" block below this check, and only run it if true. Error handling other variables that might be null because the php call isn't setting them is up to you. You can do this is multiple ways.
You should certainly cache the data so the App doesn't HAVE to connect to the internet to display something, other than that I would make sure to use asynchronous requests and the timeout feature of NSURLRequest to control your attempts to request data in the background. If you don't get the data, just keep using what you have cached.
I went to the iPhone Developer Tech Talk a few months ago and asked one of the gurus there about the lack of NSHost on the iPhone. Some code I was porting to the iPhone made significant use of NSHost throughout its networking code.
I was told that NSHost is on the iPhone, but its private. I was also told that NSHost is a synchronous API and that I shouldn't use it anyway. (If anyone could elaborate on why it shouldn't be used, as a bonus, that'd be great.)
I can see the caveats of using synchronous API's on the main thread in that they'll block until complete - and that's never a good thing with network code because there are so many factors that could cause the API to block the thread for a significant amount of time.
My solution was to write a wrapper around CFHost's asynchronous resolution functions.
The result works quite well, and I'm considering releasing it into the public domain.
But my question is this: Say my app only resolves a hostname once per run, during the connecting phase, and then cache's it for the rest of the session. During the time it is resolving, a modal screen is shown telling the user "Connecting" with a nice spinner.
Does it really matter whether or not the resolution is asynchronous?? The user has to wait to connect anyway, and the resolution is only done on the first connection. Subsequent connections use the cached result of the resolution.
When is it OK to be synchronous and when should things be asynchronous?
Your nice spinner won't spin, since the UI will get blocked as well during the synchronous call. Sure, you can make the call on a separate thread, but then you're doing essentially the same thing as the asynchronous call.