I've been getting SIGABRT when using ASINetworkQueue, and I've a suspicion that its related to threading and I'm not sure what or why. If I comment out the following code everything works, but if I leave it in, the app will just stop with a SIGABRT and no other information.
// create ASINetwork queue
if (networkQueue == nil)
{
networkQueue = [ASINetworkQueue queue];
[networkQueue setDelegate:self];
[networkQueue setRequestDidFinishSelector:#selector(requestFinished:)];
[networkQueue setRequestDidFailSelector:#selector(requestFailed:)];
[networkQueue setQueueDidFinishSelector:#selector(queueFinished:)];
[networkQueue retain];
}
// if branding url available
if ([brandingURL length] > 0) {
NSString *stringURL = [NSString stringWithFormat:#"%#/admin%#", SERVER_BASE_URL, brandingURL];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:stringURL]];
[request setUserInfo:[NSDictionary dictionaryWithObject:#"branding" forKey:#"requestType"]];
[networkQueue addOperation:request];
}
[networkQueue go];
The thread listing is in the following image gallery which is the only thing which might shed some light on whats going on with the threads.
http://imgur.com/a/msp8x
Any advice or suggestions much welcome.
Related
i want to download a file and show the progress bar
i was able to do this.
now , i want to show the progress value in a label and use this code to progress init and update label :
[queue setDelegate:self];
[queue setRequestDidFinishSelector:#selector(updateLabel)];
[queue setDownloadProgressDelegate:progress];
[queue setShowAccurateProgress:YES];
ASIHTTPRequest *request;
request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request setTemporaryFileDownloadPath:[filePath stringByAppendingString:#".download"]];
[request setAllowResumeForFileDownloads:YES];
[request setDidFinishSelector:#selector(updateLabel)];
[request setDidReceiveDataSelector:#selector(updateLabel)];
[request setShouldContinueWhenAppEntersBackground:YES];
[request setShouldAttemptPersistentConnection:NO];
[request setDownloadDestinationPath:filePath];
[queue addOperation:request];
[queue go];
but not save in the destination path !
and when i clear this code :
[request setDidReceiveDataSelector:#selector(updateLabel)];
saving done !
what is problem ?
i want to update label text when progress value changed
This is what something you need to do with the Main Thread. Updating the UI of the application is performed by the main thread rather than any of the background thread.
Or
alternatively you can use the below code snippet which works for me :
- (void)fetchThisURLFiveTimes:(NSURL *)url
{
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request addOperation:request];
[request cancelAllOperations];
[request setDownloadProgressDelegate:myProgressIndicator];
[request setDelegate:self];
[request setRequestDidFinishSelector:#selector(queueComplete:)];
[request go];
}
- (void)queueComplete:(ASINetworkQueue *)queue
{
NSLog(#"Value: %f", [myProgressIndicator progress]);
[self performSelectorOnMainThread:#selector(updateLabel) withObject:nil waitUntilDone:NO];
}
In my application i am using ASINetworkQueue method for downloading files. I have n number of buttons and for each button click different Queues will be created with multiple Requests, and starts download asynchronously (multiple download). It is working fine, but I couldn't track when each Queue completes. I have used,
[self.myQueue cancelAllOperations];
[self.myQueue setDownloadProgressDelegate:currentProgress];
[self.myQueue setDelegate:self];
[self.myQueue setShowAccurateProgress:YES];
[self.myQueue setRequestDidFinishSelector:#selector(requestFinished:)];
[self.myQueue setQueueDidFinishSelector:#selector(queueComplete:)];
and added requests as,
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:str]];
[request setDownloadProgressDelegate:currentProgress];
[request setShowAccurateProgress:YES];
[request setDelegate:self];
[request shouldContinueWhenAppEntersBackground];
[request allowResumeForFileDownloads];
[request startAsynchronous];
[self.myQueue addOperation:request];
and last, [self.myQueue go];
and the delegate method is
- (void)queueComplete:(ASINetworkQueue *)queue
{
NSLog(#"Queue completed");
}
but its not called at the end. What went wrong here? Any idea?
And also, if there are multiple Queues performing at the same time, how can we differentiate which queue is completed at the end?
Edit:
- (void)download{
UIImageView *image = (UIImageView *)[mainView viewWithTag:selectedTag];
for (UIProgressView *currentProgress in [image subviews]) {
if ([currentProgress isKindOfClass:[UIProgressView class]]) {
NSLog(#"Prog tag: %d",currentProgress.tag);
if(currentProgress)
{
currentProgress.progress = 0.0;
[[self myQueue] cancelAllOperations];
[self setNetworkQueue:[ASINetworkQueue queue]];
[[self myQueue] setDownloadProgressDelegate:currentProgress];
[[self myQueue] setDelegate:self];
[[self myQueue] setShowAccurateProgress:YES];
ASIHTTPRequest *request;
[myQueue setQueueDidFinishSelector:#selector(queueComplete:)];
for (int h = 0; h < [urlArray count]; h++) {
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:[urlArray objectAtIndex:h]]];
[[self myQueue] addOperation:request];
}
[[self myQueue] go];
}
}
}
}
You are starting the request before adding it to the queue.
[request startAsynchronous];
The starting of the request should only be handled by the queue. So remove that line and the complete callback should be called.
When you have more than one queue, you should keep a reference to each queue. You could put them in an NSMutableArray. Then in the complete callback you can check which queue is complete by checking them against the queues in your array.
EDIT:
It seems that you forget to set your myQueue iVar, so it was nil and ignored all method calls. So add:
self.myQueue = [ASINetworkQueue queue];
To have more than one queue in an array:
self.queues = [NSMutableArray array] // queues is a retained property
ASINetworkQueue *queue = [ASINetworkQueue queue];
[queues addObject:queue];
I have a problem with hiding modalviewcontroller when I connect to server with ASIHttpRequest.
I connect in background thread and show modalview in main thread.
This is my code:
[self performSelectorInBackground:#selector(loginServerRequest) withObject:nil];
- (void)loginServerRequest {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSURL *url = [NSURL URLWithString:#"https://11.111.111.11/api/login"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:[AccountSettings getCompany] forKey:#"companyName"];
[request setPostValue:[AccountSettings getEmail] forKey:#"email"];
[request setPostValue:[AccountSettings getPassword] forKey:#"password"];
[request setRequestMethod:#"POST"];
[request setTimeOutSeconds:10];
[request setValidatesSecureCertificate:NO];
[request setDelegate:self];
[request startSynchronous];
[pool drain];
}
- (void)requestFinished:(ASIHTTPRequest *)request
{
[self performSelector:#selector(hideServerConnectView) withObject:nil afterDelay:0.0];
int status = [request responseStatusCode];
NSLog(#"%i", status);
if ([self.nibName isEqualToString:#"RootViewController"]) {
if (status == 200) {
//some code
}
}
}
- (void)hideServerConnectView {
[self.parentViewController dismissModalViewControllerAnimated:NO];
}
If server responses immediately modalviewcontroller doesn't hide!
If pass some seconds then everything is okay.
What's the problem??
I changed my code like this:
[self loginServerRequest];
ServerConnectView *viewC = [[ServerConnectView alloc] init];
[self.view addSubview:viewC.view];
[self presentModalViewController:viewC animated:YES];
[viewC release];
- (void)loginServerRequest {
NSURL *url = [NSURL URLWithString:#"https://11.111.111.11/api/login"];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request setPostValue:[AccountSettings getCompany] forKey:#"companyName"];
[request setPostValue:[AccountSettings getEmail] forKey:#"email"];
[request setPostValue:[AccountSettings getPassword] forKey:#"password"];
[request setRequestMethod:#"POST"];
[request setTimeOutSeconds:10];
[request setValidatesSecureCertificate:NO];
[request setDelegate:self];
[request startAsynchronous];
}
- (void)requestFinished:(ASIHTTPRequest *)request{
[self hideServerConnectView];
int status = [request responseStatusCode];
NSLog(#"%i", status);
if ([self.nibName isEqualToString:#"RootViewController"]) {
if (status == 200) {
//some code
}
}
}
- (void)hideServerConnectView {
[self.parentViewController dismissModalViewControllerAnimated:NO];
}
And it didn't solve my problem.
Any ideas? Or something wrong?
You're mixing async and sync methods.
You set up the request as though it's an async request, but then call [request startSynchronous];.
Because of this, the delegate methods will not be called and your modal will not be dismissed.
The fix is to fire off the request async, using [request startAsynchronous];
This also means that you don't need to call performSelectorInBackground (or setup the autorelease pool in the loginServerRequest method).
In your asynchronous version, move [self hideServerConnectView]; just after [self loginServerRequest];
OR use - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(id)arg waitUntilDone:(BOOL)wait to invoke - (void)hideServerConnectView since UI update must occur on the Main Thread.
I have a project using ASIHTTP to multi download files from a site
when I add a new request:
[networkQueue cancelAllOperations];
[networkQueue setDownloadProgressDelegate:a];
[networkQueue setDelegate:self];
[networkQueue setRequestDidFinishSelector:#selector(requestDone:)];
NSURL *url = [NSURL URLWithString:#"http://www.google.com"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setDelegate:self];
[request startAsynchronous];
[networkQueue addOperation:request];
[networkQueue go];
it reported:
* Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '* -[ASINetworkQueue addOperation:]: operation is executing and cannot be enqueued'
It looks like I can not add a new request when others are running.
Welcome any comment
Thanks
interdev
If you are using a network queue, you cannot start the operation before you enqueue it. Don't call startAsynchrnous, just enqueue the operation and the network queue will start it when it dequeues it. Pretty much exactly what your error message says ;)
just remove the [request startAsynchronous]; and it will work fine for you.
hope this helps.
Thanks.
I use ASINetworkQueue to send two requests, which are in a queue.
My problem is, that I'm not able to receive notifications when
a request fails/is done.
Code:
[networkQueue cancelAllOperations];
[networkQueue setShowAccurateProgress:YES];
[networkQueue setUploadProgressDelegate:self.progressIndicator];
[networkQueue setDelegate:self];
[networkQueue setQueueDidFinishSelector:#selector(queueDidFinish)];
NSURL *urlAttachment = [NSURL URLWithString:#"http://localhost/test1.xml"]];
ASIFormDataRequest *requestFile = [[[ASIFormDataRequest alloc] initWithURL:urlAttachment] autorelease];
[requestFile setFile:filePath forKey:#"attachment[test]"];
[requestFile setDidFailSelector:#selector(test1WentWrong)];
[requestFile setDidFinishSelector:#selector(test1Done)];
[networkQueue addOperation:requestFile]; //queue is an NSOperationQueue
NSURL *url = [NSURL URLWithString:#"http://localhost/test2.xml"]];
ASIFormDataRequest *request = [[[ASIFormDataRequest alloc] initWithURL:url] autorelease];
[request setPostValue:test.filename forKey:#"filename[test]" ];
[request setDidFailSelector:#selector(test2WentWrong)];
[request setDidFinishSelector:#selector(test2Done)];
[networkQueue addOperation:request]; //queue is an NSOperationQueue
[networkQueue go];
test1WentWrong, test1Done, test2WentWrong, test2Done aren't called.
Although the request runs fine and queueDidFinish gets called.
You need to set the delegate of the individual requests rather than the queue.
Basically, if you set the didFinish and didFail selectors on the queue, the queue's delegate is called. If you set them on the request, the request's delegate is called (You can also do both, in which case both get called).
In your case, where you want to use the same delegate for both requests, but different selectors for didFail / didFinish, I can see it would make sense for the queue's delegate to be called if you didn't set a delegate for the request. Perhaps I should add this... :)
Ben