Hi. I am uploading images to a server using ASIFormDataRequest. I would like the option to cancel uploading images, so I am attempting to cancel all uploading requests, but it doesn't seem to be working.
Here is my code:
if (asiRequest) {
NSLog(#"cancel call");
[asiRequest cancel];
asiRequest.delegate = nil;
asiRequest.uploadProgressDelegate = nil;
asiRequest = nil;
progressbar.hidden=YES;
uploadinglbl.hidden=YES;
photosCountlbl.hidden=YES;
[self.spinner stopAnimating];
//[self.navigationController popViewControllerAnimated:YES];
}
Can anyone help with how I may be able to cancel all requests?
Thanks in advance.
if(![asiRequest isCancelled]) {
// Cancels an asynchronous request
[asiRequest cancel];
// Cancels an asynchronous request, clearing all delegates and blocks first
[asiRequest clearDelegatesAndCancel];
}
Related
I have an app in which i am trying to call a webservice using asihttp . Everything working fine but the problem is none of my action buttons are not working when the service call in progress after completing the call all are working fine. Below is my code
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:strURL]];
[request setAuthenticationScheme:(NSString *)kCFHTTPAuthenticationSchemeBasic];
[request setUsername:usrname];
[request setPassword:passwrd];
[request setRequestMethod:#"GET"];
[request setDelegate:self];
[request setDownloadDestinationPath:JsonPath];
[request startAsynchronous];
I have tested both with synchronous and asynchronous but same problem.
Call download method in background thread.
Once download complete call updateUI method on main thread.
Where as i know ASIHTTP calls their method in main thread. You can use AFNetWorking for faster response here
use Grand Central Dispatch (GCD) like this:
dispatch_queue_t jsonParsingQueue = dispatch_queue_create("jsonParsingQueue", NULL);
dispatch_async(jsonParsingQueue, ^{
#try {
//call webservise code
}
}
#catch (NSException * e) {
NSLog(#"Exception: %#", e);
}
dispatch_async(dispatch_get_main_queue(), ^{
//table reload or other code
});
});
I use a NSThread in order to download videos and images from a server side.It work looks and works great except the fact that when the downloading is done my GUI gets blocked until the download is complete.When the download is finished it takes a few seconds to work again.
this is how the server request is done:
- (void) repeatRequest{
NSLog(#"repeatRequest");
[NSThread detachNewThreadSelector:#selector(backgroundRequest) toTarget:self withObject:nil];
}
- (void) backgroundRequest{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURL *url = [NSURL URLWithString:myURLStr];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
[pool drain];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
//do things
}
IMPORTANTAnd I also tried to start the ASIHTTPRequest from the GUI thread but with the same behaviour.
Any idea about what could be wrong?
EDIT:
- (void) viewWillAppear:(BOOL)animated{
[super viewWillAppear:animated];
[[UIApplication sharedApplication] setStatusBarHidden:YES];
//internetReachable = [[Reachability reachabilityForInternetConnection] retain];
if(timer1 == nil)
{
timer1 = [NSTimer scheduledTimerWithTimeInterval:60.0 target:self selector: #selector(repeatRequest) userInfo: nil repeats: YES];
}
}
Try to run synchronous ASIHTTPRequest in your background thread, and handle results not in delegate method (requestFinished), but after [request startSynchronous];
I don't know anything about ASIHTTPRequest but i would assume its -startAsynchronous method already handles the background downloading for you. It all likelihood, it is returning immediately and your new thread is exiting. Also, you should just use [pool release] at the end of a thread method instead of [pool drain], it will be drained upon release, and you won't be leaking an NSAutoReleasePool. Does ASIHTTPRequest have a -startSynchronous (or just plain -start) method? Try using that within -backgroundRequest, as it should block the premature exit of that thread.
I have some code that sends multiple ASIHTTPRequests to upload and download data in a view controller. When the view controller gets dealloc'd it should clean up all unfinished requests by setting the delegate to nil.
- (void)viewDidLoad
{
// send multiple requests
[self sendRequest:someURL];
[self sendRequest:someURL];
[self sendRequest:someURL];
[self sendRequest:someURL];
}
- (void)sendRequest:(NSString*)url
{
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
ASINetworkQueue *requestQueue = [ASINetworkQueue queue];
[requestQueue setMaxConcurrentOperationCount:2];
[requestQueue setDelegate:self];
[requestQueue addOperation:request];
[requestQueue go];
}
- (void)dealloc
{
NSLog(#"cancel all operations");
for (ASIHTTPRequest *req in ASIHTTPRequest.sharedQueue.operations)
{
[req cancel];
[req setDelegate:nil];
}
[super dealloc];
}
However, if I pop this view controller before all operations have finished, I get a "message sent to deallocated instance" in ASIHTTPRequest.m complaining that the delegate went away in the code below.
/* ALWAYS CALLED ON MAIN THREAD! */
- (void)reportFailure
{
***crash here --> if (delegate && [delegate respondsToSelector:didFailSelector]) {
[delegate performSelector:didFailSelector withObject:self];
}
if (queue && [queue respondsToSelector:#selector(requestFailed:)]) {
[queue performSelector:#selector(requestFailed:) withObject:self];
}
#if NS_BLOCKS_AVAILABLE
if(failureBlock){
failureBlock();
}
#endif
}
How can I work around this?
You're creating a new queue for each request around this line of code:
ASINetworkQueue *requestQueue = [ASINetworkQueue queue];
So the loop here won't loop over the requests as it's looping over the sharedQueue, not the new one(s) you've created:
for (ASIHTTPRequest *req in ASIHTTPRequest.sharedQueue.operations)
Requests would only get added to the sharedQueue if you use [request startAynchronous] without explicitly setting a different queue.
I may be missing something, but I think waiting until dealloc is too late, you want to cancel your operations on viewWillDisappear or viewDidUnload
I'm writing test cases for a wrapper class written around ASIHTTPRequest. For reasons I can't determine, my test cases complete with failure before the ASIHTTPRequest finishes.
Here's how the program flow works.
Start in my test case.
Init my http engine object, instruct it to create a new list
Create the new ASIHTTPRequest object and set it up.
Add the request to an operation queue.
Wait until that queue is empty
Check to see if my delegate methods were called and fail the test if they weren't.
Now, most of the time everything works fine and the test passes, but some of the time it fails because my delegate methods were called AFTER the operation queue returned control to my wait method.
Test Case
// Set my flags to 'NO'
- (void)setUp {
requestDidFinish = NO;
requestDidFail = NO;
}
- (void)testCreateList {
NSString *testList = #"{\"title\": \"This is a list\"}";
JKEngine *engine = [[JKEngine alloc] initWithDelegate:self];
NSString *requestIdentifier = [engine createList:jsonString];
[self waitUntilEngineDone:engine];
NSString *responseString = responseString_;
[engine release];
GHAssertNotNil(requestIdentifier, nil);
GHAssertTrue(requestDidFinish, nil);
GHAssertTrue([responseString hasPrefix:#"{\"CreateOrEditListResult\""], nil);
}
// Puts the test into a holding pattern until the http request is done
- (void)waitUntilEngineDone:(JKEngine *)engine {
[engine waitUntilFinishedRunning];
}
// The delegate method called on successful completion
- (void)requestFinished:(NSString *)requestIdentifier withResponse:(NSString *)response {
NSLog(#"request did finish");
requestDidFinish = YES;
responseIdentifier_ = [requestIdentifier retain];
responseString_ = [response retain];
}
Engine Code
- (NSString *)createList:(NSString *)list {
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:url]];
[request addRequestHeader:#"Content-Type" value:kContentType];
[request setRequestMethod:kPOST];
request.delegate = self;
[request appendPostData:[list dataUsingEncoding:NSUTF8StringEncoding]];
NSString *requestIdentifier = [NSString stringWithNewUUID];
[operationQueue_ addOperation:request];
[operationDictionary_ setObject:request forKey:requestIdentifier];
return requestIdentifier;
}
// This is the ASIHTTPRequest delegate method that's called on success
// but it sometimes isn't called until AFTER the operationQueue finishes running
- (void)requestFinished:(ASIHTTPRequest *)request {
DLog([request responseString]);
BOOL canNotifiyDelegate = [self.delegate respondsToSelector:#selector(requestFinished:withResponse:)];
if (canNotifiyDelegate) {
NSArray *keyArray = [operationDictionary_ allKeysForObject:request];
NSString *requestIdentifier = [keyArray objectAtIndex:0];
[operationDictionary_ removeObjectForKey:requestIdentifier];
if ([keyArray count] != 1) {
ALog(#"It looks like a request was added to the operation dictionary multiple times. There's a bug somewhere.", nil);
}
[self.delegate requestFinished:requestIdentifier withResponse:[request responseString]];
}
}
- (void)waitUntilFinishedRunning {
[operationQueue_ waitUntilAllOperationsAreFinished];
}
This is the way ASIHTTPRequest works. Delegate methods are called on the main thread, and calls to delegates do not block the request thread, so it's perfectly possible your delegates will be called after the queue finishes.
ASIHTTPRequest calls delegate methods on the main thread, by default GH-Unit runs its tests on a background thread. I'm still a little hazy on exactly what was going on, but forcing my network tests to run on the main thread fixed the problem.
I implemented the following method in my network test class.
- (BOOL)shouldRunOnMainThread {
return YES;
}
Hope you guys can help me :)
In the main thread, I create a NSOperation and add it to a queue.
What that operation do is connect to a data server with NSURLConnection, save the receivedData and parse it.
Operation.m
- (void)start
{
NSLog(#"opeartion for <%#> started.", [cmd description]);
[self willChangeValueForKey:#"isExecuting"];
_isExecuting = YES;
[self didChangeValueForKey:#"isExecuting"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:_url];
[request setHTTPMethod:#"POST"];
[request setValue:[NSString stringWithFormat:#"multipart/form-data; boundary=%#", m_BOUNDARY] forHTTPHeaderField:#"Content-Type"];
[request setHTTPBody:_postData];
_connection = [[NSURLConnection alloc] initWithRequest:request delegate:self];
if (_connection == nil)
[self finish];
}
Then in this NSURL delegate method I parse the data I've just received from server.
Operation.m
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self parseItems];
}
In the data, I can found items like, for instance, screenItem, CellItem, TextItem that I send to the main thread for drawing them while arriving. (I create a UITableView if an itemTable arrives, or I create a UIWebView if an itemWeb arrives)
Using this for sending item to main thread:
Operation.m
- (void) parseItems
{
while ([_data length] > 0)
{
NSInteger type = [self _readByte];
switch (type)
{
case SCREEN:
{
[self _send: [self _readScreen]];
break;
}
case CELL:
{
[self _send: [self _readCell]];
break;
}
// ... A lot of different items
}
}
}
- (void)_send:(CItem*)_item
{
[[NSNotificationCenter defaultCenter] postNotificationName:#"newItem" object:_item];
}
Then in notification receiver:
AppDelegate.m
- (void) _newItemArrived:(NSNotification *) notification
{
[self performSelectorOnMainThread:#selector(processItem:) withObject:[notification object] waitUntilDone:NO];
}
My problem is that the UI is not painted until NSOperation finish. I thought that NSOpertion, being a different thread, would not block the main thread, but believe that is what is happening.
Some tips for this issue?
Thanks a lot for reading!
Are you using NSOperationQueue?
Check out this answer to the question NSOperation blocks UI painting? for a simple example of how to update the UI with a notification from an NSOperation running asynchronously on another thread.
UPDATE
NSURLConnection supports asynchronous connections by itself with a delegate. You should use this. If you have specific issue(s), you should describe those.
Check out the ASIHTTPRequest library.
If you really want to use this approach, you could trying running NSURLConnection synchronously (using the class method sendSynchronousRequest:returningResponse:error:). Your app would remain responsive since the connection is on a background thread. However, you would not be able to update anything until all the data is received.
So I know this is a pretty old question but I ran into the same issue and after hours of going through documentation and blogs I found a great solution in this post from Wim Haanstra http://www.depl0y.com/?p=345
Putting your NSOperation in an infinite loop until you get data back should do the trick!