HTTP requests made with NSURLConnection are event driven. This makes things a little weird when you need to issue say three requests one after another, where each request uses information returned by the previous one.
I'm used to doing it like this:
response1 = request1();
response2 = request2(response1);
response3 = request3(response2);
But the only way I could find how to do this with NSURLConnection is to have connectionDidFinishLoading: make the next request. But when the number of sequential requests grows, this can get messy.
What's the idiomatic way to handle sequential HTTP requests with cocoa?
You could wrap the requests in an NSOperation and then define operation dependencies, so that each request must wait on its dependent requests before executing.
From the Apple Docs:
Dependencies are a convenient way to execute operations in a specific order. You can add and remove dependencies for an operation using the addDependency: and removeDependency: methods. By default, an operation object that has dependencies is not considered ready until all of its dependent operation objects have finished executing. Once the last dependent operation finishes, however, the operation object becomes ready and able to execute.
I would advise you using a 3rd party library called MKNetworkKit. It can handle the hard work for you, so you can focus on the key aspects of your application. You can find it here.
You can and should use NSOperation and NSOperationQueues.
A good tutorial can be found here: How To Use NSOperations And NSOperationQueues
Related
So I need to make like 300+ get api calls and I don't want to pass them all at once and strain the server. So I was thinking of maybe doing about 5 asynchronous calls at a time.
From what I have read here operation queues sound awesome and are very useful. From the answer from this question the asynchronous example makes an operation queue and passes it into the call. I am assuming if I did something like this I could just make 5 separate queues and funnel my calls into those 5 queues (I'm assuming, haven't actually tried it since I would like to use Alamofire). Is something similar possible with Alamofire?
Network requests are automatically managed by the underlying URL Loading System, so Alamofire should be able to handle whatever you throw at it. There are ways to schedule Alamofire requests on a queue, but it shouldn't be necessary. Always better to try and measure results rather than speculate.
I need to send a server a set of requests with some data. The data in the subsequent requests will be determined based on the server response in the earlier requests. I do not want to use synchronous approach with NSURLConnection class, as it is very limiting (for one of the requests, for instance, i need to prevent redirects. According to Apple Dev documentation this can only be done with Delegate implementation).
Depending on which request in the chain it is, i need to be doing different things (send different messages to various classes).
The way i see it now, is that i have to either create n delegates for each of my requests, or create a delegate which would initWithFlag and then create the instances of that delegate with different flags, or i need to use something like a factory pattern which would be pretty similar solution to the second one.
I do not WANT to implement a delegate at all, i want to send requests with the least bit of coding possible.
I am also not looking at any frameworks (ASIHTTPRequest etc), i would like to do it with the native classes.
What would be the best approach?
I know you said you don't want to use third party frameworks, but I'd really suggest AFNetworking. With that said, you do not NEED AFNetworking or any third party library, it will just make your life easier IMHO.
So, what I have done in a similar scenario is essentially use the Command Pattern. When I want to send off one of these complicated "requests" I initialize a command object, set all of the necessary parameters and then call execute. My command object has completion and failure handlers/blocks and execute is an asynchronous call.
Within the command I have different 'steps' that are effectively synchronous and depend on each other. Let's say request A depends on B and B depends on C, the first step of the command is to execute A on it's own queue (I am using GCD with a private queue) and wait for it to finish. Once A finishes (successfully) I continue on to B and pass in any results I need from A into B. Likewise for B->C. If any of the intermediate requests fail throughout the process I can execute the failure block and handle it from where I executed the command (consumer end). If all finish successfully I execute the success block.
I prefer the encapsulation of this approach as it is very easy to re-use throughout the project, all of the intricacies are tucked away in the command's implementation.
Oh and the fact that I use callbacks/blocks I did not need to implement any delegates. In your case using the NSURL classes your command object would be the delegate of any of those instances.
I have settled on implementing the delegate after all.
The key things that tripped me were:
Do NOT declare the delegate methods in .h file. They won't work like that. Simply add them to implementation.
A delegate can be init'ed within the NSURLConnection initWithRequest method or it can be held as a property of the parent class, there is no difference.
The best way to handle multiple requests is the suggested initWithFlag. Therefore, it is best to create a delegate when initialising connection. The delegate lives long enough to perform full data transfer under ARC.
The most convenient way to cancel the redirect comes from Apple's Developer Library:
-(NSURLRequest *)connection:(NSURLConnection *)connection
willSendRequest:(NSURLRequest *)request
redirectResponse:(NSURLResponse *)redirectResponse
{
NSURLRequest *newRequest = request;
if (redirectResponse)
{
newRequest = nil;
}
return newRequest;
}
Please note that this message is sent several times during the life of the connection for undisclosed reasons. However, if the response is not an actual redirect, the redirectResponse will be nil.
Setting the request to nil will cancel the redirect, but NSURLConnection will finish processing the original data (that is, connectionDidFinishLoading message will be sent).
You can cancel this behaviour by sending this message:
[connection cancel];
I found NSNotifications to be the best way to pass results to the parent class.
I'm trying to do multiple request in background to download many jsons and check data from them but I don't know how to use AFNetworking in that case.
I tried to do like Wiki explaings but when it's going to download the second file then the app breaks. I want to do all the process in background.
Thanks
AFNetworking will definitely handle this. We use it for exchanging data with a RESTful set of services. The things to keep in mind:
An operation (eg. AFHTTPRequestOperation) can only be used once.
An operation is asynchronous.
Put your operations in an NSOperationQueue, or use AFHTTPClient (suggested) to manage the operations for you.
When sending multiple requests, always assume that the responses will come back in a random sequence. There is no guarantee that you will get the responses in the same sequence as the requests.
Hope this helps to point you towards a solution to your problem. Without more detail in your question, it's difficult to give you a specific answer.
Check out AFHTTPClient's
enqueueBatchOfHTTPRequestOperations:progressBlock:completionBlock:, which lets you enqueue multiple requests operations at once with the added bonus of having a completion handler that is called when all of those requests have finished, as well as a block for tracking the progress. Also note, that every single operation can still have its own completion handler (useful if you have to process the results of a request, for example).
If you don't need to customize the request operation (and don't need individual completion blocks), you can also use enqueueBatchOfHTTPRequestOperationsWithRequests:progressBlock:completionBlock:, which allows you to pass an array of NSURLRequest directly without having to build the operations yourself.
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.
I'm in the design stage for an app which will utilize a REST web service and sort of have a dilemma in as far as using asynchronous vs synchronous vs threading. Here's the scenario.
Say you have three options to drill down into, each one having its own REST-based resource. I can either lazily load each one with a synchronous request, but that'll block the UI and prevent the user from hitting a back navigation button while data is retrieved. This case applies almost anywhere except for when your application requires a login screen. I can't see any reason to use synchronous HTTP requests vs asynchronous because of that reason alone. The only time it makes sense is to have a worker thread make your synchronous request, and notify the main thread when the request is done. This will prevent the block. The question then is bench marking your code and seeing which has more overhead, a threaded synchronous request or an asynchronous request.
The problem with asynchronous requests is you need to either setup a smart notification or delegate system as you can have multiple requests for multiple resources happening at any given time. The other problem with them is if I have a class, say a singleton which is handling all of my data, I can't use asynchronous requests in a getter method. Meaning the following won't go:
- (NSArray *)users {
if(users == nil)
users = do_async_request // NO GOOD
return users;
}
whereas the following:
- (NSArray *)users {
if(users == nil)
users == do_sync_request // OK.
return users;
}
You also might have priority. What I mean by priority is if you look at Apple's Mail application on the iPhone, you'll notice they first suck down your entire POP/IMAP tree before making a second request to retrieve the first 2 lines (the default) of your message.
I suppose my question to you experts is this. When are you using asynchronous, synchronous, threads -- and when are you using either async/sync in a thread? What kind of delegation system do you have setup to know what to do when a async request completes? Are you prioritizing your async requests?
There's a gamut of solutions to this all too common problem. It's simple to hack something out. The problem is, I don't want to hack and I want to have something that's simple and easy to maintain.
I'm not discounting asynchronous delegate calls, but I usually end up using a threaded worker class with synchronous requests. I find it's easier in the long run to have a well defined, threaded API, instead of filling up your controller with code managing the state between asynchronous methods. You could even make asynchronous in your worker thread, although usually it's easier to use the synchronous methods unless they don't support a feature you need to use. Of course, all of this depends on the circumstances, I can think of many situations where simply using the asynchronous methods would be the best route.
Definitely consider NSOperationQueue if you go this route; it greatly simplifies creating multiple worker threads, and it also supports priorities and dependancies between operations. Right now there are some problems with it on 10.5, but I haven't heard of any issues on the iPhone.
An official response is that you should almost always go asynchronous and that synchronous is bad. I found ASIHTTPRequest makes asynchronous requests easy-peasy.
I don't think that there's a "right" answer. It seems that you understand the compromises involved and you just need to make your design around those.
A few extra random points: sometimes your application forces a particular approach. For example, many of the convenience (i.e., synchronous) methods won't allow authentication. For me that meant that my decision was made.
For Yummy I ended up not using threads. I made all my network calls asynchronous and I used the default XML parser (which works using call backs). Since it's all event driven and each unit is small it allows the GUI to be pretty fluid without having the complexity of threading.
I use a state machine to figure out why I'm getting a particular response, and a queue so that I only need to have a single operation "in flight" at any given time. There's a distinct order to most requests so I have no need for a priority system.
The networking code is the most complex in my app and it took a long time to get working much less robust!
I personally look at what is being done, I will ususally use an asyc request to ensure that the UI doesn't block, however, I MAY during the course of that request disable the UI of my application.
A prime example of this is in an application that I built with a "search" button. Once the search was triggered as an async request I would disable the button until the response came back, effectivly limiting the ability for the user to spawn a second asyc request.
Doing this, at least I can prevent the need for priorites, granted this only works if you can in an easy to do way, limit your users to one action at a time.
I'd recommend the asychronous way, no question. Then, load the information only when needed, and use a delegate system to give that information to the correct object.
You don't want to block the UI. Ever. And loading information asynchronously allows you better control over what's happening so you can throw up an error message if needed.
Just a thought: If you want to use the Unit Testing framework for the iPhone, you may want to have synchronous functionality, as that could make writing the tests easier.
However, some of your APIs may not work synchronously, so you need to turn them into sync tasks. Provided the code that performs the unit testing runs in its own thread, you can write a wrapper that will wait until the async task has finished.
To accomplish that, you'd use a semaphore: Your wrapper function starts the async operation and then uses the semaphore to block itself (i.e. puts itself to sleep). The callback that signals the end of the async event releases the semaphore, so that the sleeping wrapper thread can continue and return.
I would use dispatch_async with synchronous. This way, you have the advantage of no delegates/NSNotifications and it is non-blocking
- (NSArray *)users {
if(users == nil) {
users = do_sync_request();
}
return users;
}
// now when calling the users method, do this
- (NSArray *)getUsers {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSArray *users = [self users];
dispatch_sync(dispatch_get_main_queue(), ^{
return users;
}
}
}
Why can't you use an asynchronous request like so:
- (NSArray *)users {
if(users == nil && !didLaunchRequestAlready )
users = do_async_request // Looks good to me
return users;
}
Asynchronous is absolutely the only option - the only real question is if you want to start using separate threads, or if you want to just use the asynch calls. Start there and look at managing threads if you really need to.