I'm setting up a class to manage the download of some data. Due to the spec it has to be downloaded multiple times (as it may change). I can't change that but I have a question.
If I create a class that is dedicated to downloading the data so it is an NSURLConnectionDataDelegate etc...
Can I store the NSURLConnection as a property and set it up in the init and then reuse the same connection each time?
Or should I store the NSURLRequest and use the same request in a new connection each time?
The reason I ask is that the docs for NSURLConnection state...
"You cannot reschedule a connection after it has started."
and I'm not 100% sure what that means.
Yes, as long as each time you have a unique object that creates the NSURLConnection. This is simply stating you can't have the same object "reschedule" a connection, mid connection.
Never hurts to run a simple test.
Related
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.
What would be the most appropriate way to chain asynchronous NSURLConnections? For example, I need to register a user with a web service. The workflow would be as follows:
Get Register Token => Use token to Register => Get Login Token => Use token to Login.
I know how to create an asynchronous NSURLConnection, but I'm unsure how to make sure the previous connection has finished before moving on. I know I can achieve this using NSURLConnection sendSynchronousRequest but I don't like my main thread being blocked while these chained requests happen.
We did EXACTLYA this when we built our first version of SignMeOut for iPhone. We created a subclass of NSUrlconnection and gave it an identifying tag do in the connectionDidFinish you would be able to use a simple switch/case with an enum. Works great - you can see the whole flow and example and code in our blog
http://www.isignmeout.com/multiple-nsurlconnections-viewcontroller/
UPDATE
I've modified the NSURLConnection subclass into a much simpler Category. Most of the usage is the same but cleaner using the same class
https://github.com/Shein/Categories
You can look at connectionDidFinishLoading to start another asynchronous connection. For the conditions as to which connection ended, you can keep references to the connections in case other connections are also expected to finish(probably not needed in your case). Make your class follow the NSURLConnectionDelegate and fire the appropriate connections in the connectionDidFinishLoading delegate method. You can also use the connectionDidReceiveData: method to check for credentials, etc received from the service. Go through the documentation too.
You have different options:
create a queue using a mutable array or dictionary
create an NSOperationQueue kind of easy if you use it in combination
with the new only ios5 API for NSUrlConnection
third parties lib such as AFNetworking
Block GCD grouping them (hard for NSRunLoop reasons, pay attention in wich thread the connection is running in)
I have a few apps that I am trying to develop a reusable URL connection layer. I have done some research and am struggling between architectures. Specifically the APIs this layer utilizes.
In the past, I have used NSURLConnection and NSOperation on a separate RunLoop. This seems overkill. I've seen libraries that subclass NSURLConnection. Others have a singleton Engine object that manages all requests.
The Engine and/or NSURLConnection seem best to me. But I am asking for input before I go too far down one road. My goals would be:
Ability to cancel a request
Concurrent requests
Non-blocking
Data object of current open requests
Any direction or existing references with code samples would be greatly appreciated.
I'm not sure about a "data object of current open requests", but ASIHTTPRequest does the first three and is very easy to use.
Update
Actually, it looks like ASINetworkQueue may fulfill your last bullet point.
I personally use a singleton engine with my large Apps though it might not always be the best case. All the URL's I use require signing in first, figured it would be best if one Class handles all of the requests to prevent multiple URLS from signing into the one location.
I basically create a protocol for all my different connection classes into my singleton and pass the delegate of both the calling class and the singleton into it. If an error occurs its passed to the singleton so it can deal with it, if it completes it returns the data to the calling class.
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
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