How to wait for a certain status of a NSURLConnection - iphone

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.

Related

UIImageView+AFNetworking image request queue blocks other network requests from RestKit

I am downloading Data with RestKit by creating RKObjectRequestOperations and adding them to RestKit's queue:
RKObjectRequestOperation *operation = [RK objectRequestOperationWithRequest:request
success:...
failure:...];
[RK enqueueObjectRequestOperation:operation];
That one works well. Additionally, this data is displayed in a list view that contains UIImageViews displaying related user icons. These user icons, however, are not downloaded via RestKit, but via the underlying AFNetworking library. UIImageView+AFNetworking does the job also pretty well (including the caching):
[self setImageWithURLRequest:userIconRequest
placeholderImage:anonymousUser
success:nil
failure:...];
The problem is that those 15 user icon requests from the image views block the processing of the RestKit request that should be loading the next page immediately. I can see the list displaying the "loading" row as well as the first user icons. In the moment the last image finished loading the next page appends itself.
Looking into the implementation of UIImageView+AFNetworking shows that it is using an own NSOperation queue instance that is serializing requests. However that should not interfere with RestKit I suppose.
Also adding NSOperationQueuePrioritys to all requests does not change a thing. Maybe internally, network requests are serialized in a different way? How can I prioritize those requests?
Thanks in advance.
NSURLConnection has an undocumented maximum number of connections.
Additionally, UIImageView+AFNetworking's operation queue has NSOperationQueueDefaultMaxConcurrentOperationCount maximum current requests, which is likely a bad choice for your use case according to this convincing-sounding AFNetworking discussion.
You need to throttle. I see two simple solutions:
Modify UIImageView+AFNetworking to have, say, 4 maximum concurrent operations.
Modify UIImageView+AFNetworking to use the same operation queue as RestKit, in which case the priority you set will matter.

Download queue in iPhone

What's the best way to implement a download queue in iPhone? Can this be done with the ASIHTTPRequest library?
I think it is not difficult to implement one. Here is my strategy:
1/ You have an array of tasks (to be simple, just an array of urls) to store the list of download urls
2/ You can have a singleton object that Whenever, you put url into the queue, you inform it.
3/ When the singleton object is informed, it checks if it is free to do the job. If it is, it takes the first url out of the queue, call asynchronous request to the server. It set its state to be busy.
4/ When the asynchronous request call back, the singleton checks the queue again to see if it is empty. If it is not, then get the next url, do the step 3 again. If it is empty, then the singleton object set its state to be free, then the next object put something into the download queue can inform the singleton object.
You can have many asynchronous request at the time by checking against a constant number. And yes, you can call asynchronous request with ASIHTTPRequest library.
I don't know if there is any library do this job for you, but I think it is easy to implement.
ASIHTTPRequest includes the ASINetworkQueue object which can be used as a download queue, see:
http://allseeing-i.com/ASIHTTPRequest/How-to-use#about_ASINetworkQueues
You can then track overall process like so:
http://allseeing-i.com/ASIHTTPRequest/How-to-use#tracking_download_progress_for_a_set_of_requests

what exactly NSUrlConnection ASynchronous means?

i am getting confused what is the difference between Synchronous NSUrlConnection and ASynchronous NSUrlConnection?is there Synchronous or ASynchronous? if we use detachNewThreadSelector in connectionDidFinishLoading method,is it
ASynchronous NSUrlConnection? which is the best way?any tutorial ...
Synchronous means that you trigger your NSURLConnection request and wait for it to be done.
Asynchronous means that you can trigger the request and do other stuff while NSURLConnection downloads data.
Which is "best"?
Synchronous is very straightforward: you set it up, fire it, and wait for the data to come back. But your application sits there and does nothing until all the data is downloaded, some error occurs, or the request times out. If you're dealing with anything more than a small amount of data, your user will sit there waiting, which will not make for a good user experience.
Asynchronous requires just a little more work, but your user can do other stuff while the request does its thing, which is usually preferable. You set up some delegate methods that let you keep track of data as it comes in, which is useful for tracking download progress. This approach is probably better for most usage cases.
You can do both synchronous and asynchronous requests with NSURLConnection. Apple's documentation provides a clear explanation of the two approaches and delegate methods required for the latter approach.
It seems that you're conflating synchronous/asynchronous connections and threading. In my app I used asynchronous connections as an alternative to threading.
Let's say you want to download a big file without causing the UI to freeze. You have two basic options:
Asynchronous connection. You start with + connectionWithRequest:delegate: (or one of the other non-autorelease options) and it downloads bits of the file, calling your delegate when interesting thing happen. The runloop is still going, so your UI stays responsive. Of course you have to be careful that your delegate don't go out of scope.
Synchronous. You start the connection with + sendSynchronousRequest:returningResponse:error: but the code waits until the download is complete. You'll really need to spawn a new thread (or one of the higher level threading operations that Cocoa supports) or the UI will block.
Which option is "best" or the least painful will depend on the architecture of your application and what you're trying to achieve. If you need to create a thread for a long running process anyway, you might go with the second option. In general I would say the first option is easiest.
It's all pretty well documented on Apple's Developer site.
Something which hasn't been mentioned in the other responses is the size of the request. If you're downloading a large file, for example, then using an asynchronous connection is better. Your delegate will receive blocks of data as they arrive. In comparison, the synchronous method will wait for all the data before making it available to you. The delegate can start processing the response sooner (better user experience), or save save it to a file instead of memory (better resource usage). You also have the option to stop the response without waiting for all the data.
Basically, the asynchronous method gives you more control over the connection but at the cost of complexity. The synchronous method is much simpler, but shouldn't be used on the main UI thread because it blocks.
In response to the other answers regarding the file size: I think file size doesn't matter. If the server responds really slowly and you're loading data synchronous your UI still freezes, even if you're loading a small amount of data, like 3k.
So I'd go for the asynchronous option in every situation, cause you never know what you're going to get with regards to file size, server responsiveness or network speeds.

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

Is there any sample code to do iPhone mulitithreading tasks?

I have some slow internet task to save and load file, I'd like to do those slow tasks in some background thread. I am wondering whether that's doable, and if it is, any sample code?
Then after it is finished, I'd like it to notice back to the main thread, so that I could update the UI.
Take a look at NSURLConnection. It will load an NSURL (using NSURLRequest) in the background, and send delegate methods regarding its status.
Ultimately the device you are running your code on has a single processor and cannot possibly load large quantities (gigabytes) of data. The best route, by is likely that suggested by Ben (NSURLConnection asynchronously) which gives you the added advantage of being able to cleanly cancel and handle error messages. While it isn't technically threaded in the way you probably think you want it to be, it is well integrated with the event loop and is non-blocking. If that is still not enough, I would suggest looking at NSOperation and NSOperationQueue. You can fire off an NSOperation sub-class object and perform the download there (I would still advise doing it asynchronously there so as to enable canceling, pausing, etc).
Log in to the iPhone Developer Center and search for Introduction to Threading Programming. Or, maybe you can log in and use this link:
http://developer.apple.com/iphone/library/documentation/Cocoa/Conceptual/Multithreading/Introduction/chapter_1_section_1.html#//apple_ref/doc/uid/10000057i-CH1-SW1
If you do decide you need a background thread even after using asynchronous HTTP calls to gather the data, don't forget to wrap the background thread code in a new NSAutoReelasePool and then release it at the end.