series of http asynchronous request calls - iphone

I need to make a series of http asynchronous request calls within a for loop . But then i would need to wait for the download to complete for a response before making the next request without crashing. So using NSNotification (or anything else) how can i handle this.

When you do a async request you wont be required to wait. However you need to handle the responses correctly. You can check the ASIHttpRequest library which currently seems to be the favorite of developers on SO.
If you have to wait for the response then you are not doing it asynchronously.
Coming to using NSNotification, a better cleaner and simpler approach would be to use protocols. This way you implement the delegate and send you next request everytime the delegate method is called.

You want to run a number of serial requests in the background and wait for each request to finish before the next gets started. This is no different than running anything else in the background. Here is something I whipped up:
[self performSelectorInBackground:#selector(runRequests) ...];
- (void)runRequests
{
for (int i = 0; i < self.urls.count; i++) {
NSURL *url = [self.urls objectAtIndex:i];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous]; // Note: not asynchronous
// Handle response ...
ALog(#"%# completed", url);
}
[[NSNotificationCenter defaultCenter]
postNotificationName:#"all requests completed!" object:nil];
}
I'm using ASIHTTRequest here, but using NSURLRequest works just as well in this case. The important thing is that the request is run to completion.

You can do it by using threads as follows
[NSThread detachNewThreadSelector:#selector(myMethod1) toTarget:self withObject:nil];
[NSThread detachNewThreadSelector:#selector(myMethod2) toTarget:self withObject:nil];
[NSThread detachNewThreadSelector:#selector(myMethod3) toTarget:self withObject:nil];
and so on...........
You can pass your requests in these methods asynchronously.

Related

ASIHTTPRequest in ASINetworkQueue: Cancel request while queue is running

I am using ASIHTTPRequest (I know, I know, it is not being maintained - that doesn't matter; it works and it is what my app is built on) to run a series of HTTP requests through ASINetworkQueue.
The problem is that my queue will have many requests (thousands), and it will take a while to run. In the time that it is running, some of the data in the app may have changed which would make some of the request unnecessary. I would like to run a validation method on each request right before it runs, and if the validation method does not check out, then it will cancel that request and go on to the next one.
Right now, I am using the following code to create my ASIHTTPRequests:
ASINetworkQueue *myQueue = [ASINetworkQueue queue];
NSURL *URL = [NSURL URLWithString:#"http://mywebsite.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setStartedBlock:^{
NSLog(#"Request started: %#", request.url.absoluteString);
}];
[request setCompletionBlock:^{
NSLog(#"Request completed: %#", request.url.absoluteString);
// do some code here to clean up since it's finished
}];
[myQueue addOperation:request];
My current thinking is to put something into the startedBlock, so it would do:
[request setStartedBlock:^{
NSLog(#"Request started");
if (![self myValidationMethod]) {
[request cancel]; // <----------
}
}];
However when I do this, I get the following warning from Xcode:
"Capturing 'request' strongly in this block is likely to lead to a retain cycle."
First, is this the right method to go about doing this? I can't seem to find a way to remove a specific ASIHTTPRequest from an ASINetworkQueue. Second, is this warning from Xcode something that I will need to worry about?
About the warning you capture the blocks 'container' and form a cycle... just say:
__weak ASIHTTPRequest *rw = request;
and use that in the block.
as for the started block approach. doesnt sound perfect to me but I dont know a better approach...

iPhone:UI blocked when downloading data using NSURLConnection

I am using the NSURLConnection to download a video file from the server, at the same time playing the video by passing different url link to the movieplayer.
The problem is some blocking of the UI. During downloading we are unable to interact with the UI, like player zoom, pause button are blocked.
Code is like this for connection:_
connection1=[[NSURLConnection alloc] initWithRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:urlStr]] delegate:self];
in same mithod we are calling the
[playerInstance Play]
Please can you explain me where the problem is.
I can't understand your problem exactly. But I think you doing the two works (downloadig, playing file) on a same thread, probably main thread. So this may happen. So try to run the two processes in a separate threads.
[self performSelectorOnMainThread:#selector(playfile:) withObject:nil waitUntilDone:NO];
[self performSelectorInBackground:#selector(downloadfile:) withObject:nil];
You should make function for NSUrl operation and if it is already made call this function in following way for asynchronous communication.
[self performSelector:#selector(method) withObject:nil afterDelay:1];

Cancelling ASIHTTPRequest

Where is the right place to cancel an ongoing request of ASIHttpRequest? This is how I do my cancellation but it keep on crashing when I transfer from one viewcontroller to another without letting the request to finish. The cancellation fo request works fine, but when switch back to the first Viewcontroller it will crash.
-(void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
if(!DID_FINISH_REQUEST)
{
[requestNewReleases setDelegate:nil];
[requestNewReleases cancel];
[requestNewReleases clearDelegatesAndCancel];
}
}
In the ASIHttpRequest documentation there is an example of a request being cancelled in the dealloc method:
Safely handling the delegate being deallocated before the request has
finished
Requests don’t retain their delegates, so if there’s a chance your
delegate may be deallocated while your request is running, it is vital
that you clear the request’s delegate properties. In most
circumstances, if your delegate is going to be deallocated, you
probably also want to cancel request, since you no longer care about
the request’s status.
In the example below, our controller has an ASIHTTPRequest stored in a
retained instance variable. We call the clearDelegatesAndCancel method
in it’s dealloc implementation, just before we release our reference
to the request:
- (void)dealloc
{
[request clearDelegatesAndCancel];
[request release];
...
[super dealloc];
}
It depends on your architecture and application needs - eg. If there are multiple http requests only some of which need to cancel?
Then solution -
for (ASIHTTPRequest *req in ASIHTTPRequest.sharedQueue.operations)
{
[req cancel];
[req setDelegate:nil];
}
This will cancel and remove the delegate of all in progress requests that have been assigned to the default queue.

iOS: ASIHTTPRequst synchronous on background selector bad idea?

I was using NSURLConnection in a synchronous way before running on a background selector, so when I moved over to ASIHTTPRequest I did the same with this framework.
So, is it a bad idea to do something like the following?
// From another method
[self performSelectorInBackground:#selector(callDatasource) withObject:nil];
- (NSData *)callDatasource {
NSAutoreleasePool *apool = [[NSAutoreleasePool alloc] init];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:someURLthatIamusing];
[request setTimeOutSeconds:50.0];
[request startSynchronous];
NSError *error = [request error];
NSData *returnedData;
if (!error) {
returnedData = [request responseData];
} else {
// do something with error
}
[self performSelectorOnMainThread:#selector(done) withObject:nil waitUntilDone:NO];
[apool release];
return returnedData;
}//end
What would be the advantage to use the ASIHTTPRequest and asynchronous methods along with the delegate methods?
From experience, sometimes odd things can happen when using ASIHTTPRequest synchronous requests off a secondary thread: the download activity icon in the status bar not disappearing upon download completion is one issue I've noticed from time to time. I've had no major problems in the past, but I use the asynchronous methods now rather than your approach. The ASI asynchronous methods are by the nature of being a widely used library more highly tested than my own implementation could ever be.
There are a number of advantages with using the asynchronous methods - you mention the delegate methods, but the latest release of ASI actually also supports blocks, which is a great leap forward (dealing with multiple synchronous calls used to be a bit of a pain due to the shared delegate methods (or unique delegates for each asynchronous call). But with blocks you can now get rid of the delegates entirely. I've found them to be really useful. Plus if you use multiple contributors it can make readability a lot easier.
Also, by doing it Async, you can more easily track progress through the setProgressDelegate command.

Making multiple service calls on iPhone app initialization

I need to make multiple asynchronous service calls in the application:didFinishLaunchingWithOptions: method from my application delegate in order to retrieve some data from a service to be used across various controllers in my app. I have control over the service, and I've designed the API to be as RESTful as possible, so I need to make multiple calls during app initialization.
What I want to do is to show a loading view with a progress indicator - similar to the default splash screen from Default.png - and remove that view once the service calls have completed and I have the initial values I need. This is pretty easy to do if there's only one service call, since I can simply hook that logic into the connectionDidFinishLoading: delegate method of NSURLConnection by hiding the loading view and displaying the root controller.
However, with multiple service calls, it becomes tricky. I can "chain" everything together and fire off one request, wait for it to finish/fail, then fire off the second request, and so on until I get to the last request. In the last request, I then hide the loading view and display the normal view. However, this can get unwieldy with multiple service calls, and the code becomes hard to understand and follow.
Any suggestions on the best approach for this?
I'm thinking one solution is to have a singleton class responsible for making service calls and app initialization. The singleton object will fire off all necessary requests in parallel on start, and each fail/finish callback will check if every request has finished. If all requests have finished, then it can call some method in the application delegate and tell it to hide the loading view, show the root controller, etc.
Thoughts?
Another possibility is to have each service completion callback notify (NSNotification) the controller of the progress indicator that progress has been made. You could also tell the controller of the progress indicator of how many request you were planning to make, and let it keep score, and itself do a callback when it thinks everything is done.
I am doing something similar with an NSOperationQueue that is configured to just run 1 operation at a time. See for example WeaveEngine.m and it's synchronizewithServer:credentials: method. I queue up all the separate operations, which are mostly async network calls.
you could use NSThreading and make synchronous calls in separate threads for each thing you need to get like
[NSThread detachNewThreadSelector:#selector(getDataRequest1:) toTarget:self withObject:urlRequest];
[NSThread detachNewThreadSelector:#selector(getDataRequest2:) toTarget:self withObject:urlRequest];
[NSThread detachNewThreadSelector:#selector(getDataRequest3:) toTarget:self withObject:urlRequest];
then in the selector for each thread do something like
- (void) getDataRequest1:(NSURLRequest*)urlRequest {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSHTTPURLResponse *urlResponse;
NSError *error;
NSData *responseData = [NSURLConnection sendSynchronousRequest:urlRequest returningResponse:&urlResponse error:&error];
NSString *responseString = [[NSString alloc] initWithData:responseData encoding:NSUTF8StringEncoding];
if ([urlResponse statusCode] < 200 || [urlResponse statusCode] > 299) {
//request probably failed
}else{
[self performSelectorOnMainThread:#selector(completeRequest1:) withObject:responseData waitUntilDone:NO];
}
[pool drain];
[responseString release];
[urlRequest release];
}
of course it really depends on how many requests/threads you are wanting to spawn.
and you will need to keep track of how many you spawn vs how many finish so you can properly stop your spinner.