ASINetworkQueue some image download fails - ios

I am downloading a bunch of images via ASINetworkQueue. I have no problems in the simulator, but on the iPad some of the images (each time they are different) are not downloaded. How can I fix this?
Here is the code:
Queue Creation:
if (addedPaintings > 0) {
[currentPaintingsArray addObjectsFromArray:objectsToAdd];
[unseenPaintings addObjectsFromArray:objectsToAdd];
[self downloadImages];
}
// update plist file if data was altered.
if (addedPaintings > 0 || removedPaintings > 0)
[currentPaintingsArray writeToFile:dataFilePath atomically:YES];
else
[self completeSync:request.responseStatusCode];
}
Image Download method:
- (void) downloadImages {
[networkQueue reset];
[networkQueue setDelegate:self];
[networkQueue setShowAccurateProgress:YES];
[networkQueue setDownloadProgressDelegate:self.progressView.customView];
[networkQueue setQueueDidFinishSelector:#selector(imageQueueDownloadComplete:)];
for (NSDictionary *dict in [Globals sharedGlobals].unseenPaintings) {
NSString *link = [dict objectForKey:#"link"];
NSString *smallLink = [dict objectForKey:#"smallLink"];
if ([link length] != 0) {
NSURL *url = [NSURL URLWithString:[[URL stringByAppendingString:GALLERY] stringByAppendingString: link]];
ASIHTTPRequest *downloadRequest = [[ASIHTTPRequest alloc] initWithURL:url];
[downloadRequest setDownloadDestinationPath:[documentsDirectory stringByAppendingPathComponent:link]];
[downloadRequest setDidFailSelector:#selector(imageDownloadFailed:)];
[downloadRequest setDidFinishSelector:#selector(imageDownloadComplete:)];
[downloadRequest setUserInfo:dict];
[downloadRequest setDelegate:self];
[networkQueue addOperation:downloadRequest];
[downloadRequest release];
NSURL *urlCarousel = [NSURL URLWithString:[[URL stringByAppendingString:WS_IMAGES] stringByAppendingString: smallLink]];
downloadRequest = [[ASIHTTPRequest alloc] initWithURL:urlCarousel];
[downloadRequest setDownloadDestinationPath:[documentsDirectory stringByAppendingPathComponent:smallLink]];
[downloadRequest setDidFailSelector:#selector(imageDownloadFailed:)];
[downloadRequest setUserInfo:dict];
[downloadRequest setDelegate:self];
[networkQueue addOperation:downloadRequest];
[downloadRequest release];
}
}
[networkQueue go];
}

Based on the comments you've left to the question, (Specifically: Also, if I change the download method from networkQueue to [downloadRequest startAsynchronous], everything works.) it may be that your request is timing out when being run synchronously.
Another thing you should know is that the "ASI network classes" are no longer being maintained. The developer offers several alternatives in his blog post announcing the end-of-life of that software.

Related

Asynchronous request running slowly - iOS

I have an app which downloads a set of photos from a server. I am using an Asynchronous request because I don't want the UI to be blocked. However, I am finding that the request is very slow and takes ages to load.
I know you can set the queue type to [NSOperationQueue mainQueue] but that just puts the Asynchronous request back on the main thread which defeats the whole point of making the request Asynchronously in the first place.
Is there anyway to speed up the request or to tell iOS: "Run this request in the background, but do it ASAP, don't leave it till the end of the queue"???
Here is my code:
// Set up the photo request.
NSURL *url = [NSURL URLWithString:[NSString stringWithFormat:PHOTO_URL, pass_venue_ID, PHOTO_CLIENT_ID, PHOTO_CLIENT_SECRET]];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// Begin the asynchromous image loading.
[NSURLConnection sendAsynchronousRequest:urlRequest queue:queue completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
if (error == nil) {
// Convert the response data to JSON.
NSError *my_error = nil;
NSDictionary *feed = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableLeaves error:&my_error];
// Check to see if any images exist
// for this particular place.
int images_check = [[NSString stringWithFormat:#"%#", [[[feed objectForKey:#"response"] valueForKey:#"photos"] valueForKey:#"count"]] intValue];
if (images_check > 0) {
// Download all the image link properties.
images_prefix = [[[[feed objectForKey:#"response"] valueForKey:#"photos"] valueForKey:#"items"] valueForKey:#"prefix"];
images_suffix = [[[[feed objectForKey:#"response"] valueForKey:#"photos"] valueForKey:#"items"] valueForKey:#"suffix"];
images_width = [[[[feed objectForKey:#"response"] valueForKey:#"photos"] valueForKey:#"items"] valueForKey:#"width"];
images_height = [[[[feed objectForKey:#"response"] valueForKey:#"photos"] valueForKey:#"items"] valueForKey:#"height"];
// Set the image number label.
number_label.text = [NSString stringWithFormat:#"1/%lu", (unsigned long)[images_prefix count]];
// Download up to 5 images.
images_downloaded = [[NSMutableArray alloc] init];
// Set the download limit.
loop_max = 0;
if ([images_prefix count] > 5) {
loop_max = 5;
}
else {
loop_max = [images_prefix count];
}
for (NSUInteger loop = 0; loop < loop_max; loop++) {
// Create the image URL.
NSString *image_URL = [NSString stringWithFormat:#"%#%#x%#%#", images_prefix[loop], images_width[loop], images_height[loop], images_suffix[loop]];
// Download the image file.
NSData *image_data = [NSData dataWithContentsOfURL:[NSURL URLWithString:image_URL]];
// Store the image data in the array.
[images_downloaded addObject:image_data];
}
// Load the first image.
[self load_image:image_num];
}
else if (images_check <= 0) {
// error...
}
}
else {
// error
}
}];
Thanks for your time, Dan.
i think your problem isnt the request running slow, its that you are updating UI elements not on the main thread, surround any UI updates (like setting the text on labels) with
dispatch_sync(dispatch_get_main_queue(), ^{
<#code#>
});
As Fonix said its not iOS that responding slow but dataWithContentsOfURL doesn't work in background thread. Apple's recommendation is that you should use NSURLConnection asynchronously with delegates
- didReceiveResponse
- didReceiveData
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:theURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:_mAuthenticationTimeoutInterval];
In these methods you can make use of chunks of data as well.
If you actually want these multiple downloads to be faster you should use parallel downloading using NSOperationQueue. You can refer enter link description here
I think a good solution could be using AFNetworking when combined with NSOperation, check this code I wrote to do more than one operation asynchronously
NSMutableArray *operations = [[NSMutableArray alloc] init];
for(NSObject *obj in caches) {
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
[request setURL:url];
//...set up your mutable request options here
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.responseSerializer = [AFJSONResponseSerializer serializer];
operation.responseSerializer.acceptableContentTypes = [NSSet setWithObject:#"application/json"];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSInteger statusCode = operation.response.statusCode;
if(statusCode==200) {
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"API Call error:%#", error.localizedDescription);
}];
[[requestManager operationQueue] addOperation:operation];
[operations addObject:operation];
if([operations count] >= MAX_API_CALL) break;
}
[AFHTTPRequestOperation batchOfRequestOperations:operations progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
} completionBlock:^(NSArray *operations) {
NSError *error;
for (AFHTTPRequestOperation *op in operations) {
if (op.isCancelled){
}
if (op.responseObject){
// process your responce here
}
if (op.error){
error = op.error;
}
}
}];

Memory issue while uploading multiple images to server

I am uploading multiple images to server using ASIHTTPRequest.
-(void)uploadImagesToServer
{
[[self networkQueue] cancelAllOperations];
// Creating a new queue each time we use it means we don't have to worry about clearing delegates or resetting progress tracking
[self setNetworkQueue:[ASINetworkQueue queue]];
[[self networkQueue] setDelegate:self];
[[self networkQueue] setRequestDidStartSelector:#selector(uploadRequestStarted:)];
[[self networkQueue] setRequestDidFinishSelector:#selector(requestFinished:)];
[[self networkQueue] setRequestDidFailSelector:#selector(requestFailed:)];
[[self networkQueue] setQueueDidFinishSelector:#selector(queueFinished:)];
[[self networkQueue] setUploadProgressDelegate:self.uploadBar];
[[self networkQueue] setShowAccurateProgress:YES];
[ASIHTTPRequest setDefaultTimeOutSeconds:30];
for (int i = 0; i< appDelegate.selImageDetails.count; i++) {
NSMutableDictionary *dic = [appDelegate.selImageDetails objectAtIndex:i];
NSString *orderid = [[NSUserDefaults standardUserDefaults] objectForKey:#"orderId"];
if ([[dic objectForKey:#"Status"] isEqualToString:#"N"] || [[dic objectForKey:#"Status"] isEqualToString:#"Failed"])
{
NSURL *url = [NSURL URLWithString:#"http://180.151.100.53:9776/App_Frame_IT/UploadImage"];
NSLog(#"UPLOAD IMAGE ARRAY == %#",dic);
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc]init];
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
[request addPostValue:orderid forKey:#"OrderId"];
[request addPostValue:[dic objectForKey:#"ImageName"] forKey:#"imgName"];
[request addPostValue:#"10" forKey:#"appId"];
[request addPostValue:[dic objectForKey:#"Frame"] forKey:#"frameSize"];
[request addPostValue:[dic objectForKey:#"Quantity"] forKey:#"Quantity"];
NSString *imgCount = [NSString stringWithFormat:#"%d", [appDelegate.selImageDetails count]];
[request addPostValue:imgCount forKey:#"totalimages"];
[request addPostValue:[dic objectForKey:#"paperQuality"] forKey:#"paper_quality"];
NSURL *assetURL = [dic objectForKey:#"assetPathURL"];
ALAssetsLibrary *assetLibrary=[[ALAssetsLibrary alloc] init];
[assetLibrary assetForURL:assetURL resultBlock:^(ALAsset *asset) {
ALAssetRepresentation *rep = [asset defaultRepresentation];
Byte *buffer = (Byte*)malloc(rep.size);
NSUInteger buffered = [rep getBytes:buffer fromOffset:0.0 length:rep.size error:nil];
NSData *data = [NSData dataWithBytesNoCopy:buffer length:buffered freeWhenDone:YES];//this is NSData may be what you want
//NSLog(#"returned Image ====> %#", data);
// UIImageView *testImageView = [[UIImageView alloc]initWithFrame:CGRectMake(50, 10, 50, 50)];
NSLog(#"FUll REsolution Image Size in MB = %.2f",(float)data.length/1024.0f/1024.0f);
//[data writeToFile:photoFile atomically:YES];//you can save image later
//NSData *imageData = [[NSData alloc] initWithContentsOfMappedFile:[dic objectForKey:#"Path"]];
[request addData:data withFileName:[dic objectForKey:#"ImageName"] andContentType:#"image/png" forKey:#"uploadfile"];
//[data release];
NSLog(#"requestGenrated table count---%d ",[appDelegate.selImageDetails count]);
NSString *requestUserName = [NSString stringWithFormat:#"upload%i",i];
[request setUsername:requestUserName];
[request setUserInfo:[NSDictionary dictionaryWithObject:[dic objectForKey:#"unique"] forKey:#"uniqueId"]];
[request setTag:i];
[request setShowAccurateProgress:YES];
[request setRequestMethod:#"POST"];
[request setShouldContinueWhenAppEntersBackground:YES];
[[self networkQueue] addOperation:request];
[dic setObject:#"Y" forKey:#"requestGenrated"];
[appDelegate.selImageDetails replaceObjectAtIndex:i withObject:dic];
NSLog(#"Upload Request Created");
} failureBlock:^(NSError *err) {
NSLog(#"Error: %#",[err localizedDescription]);
}];
[pool drain];
}
else
{
NSLog(#"((Image already uploaded))");
}
}
failedRequests = 0;
[networkQueue setShouldCancelAllRequestsOnFailure:YES];
[[self networkQueue] go];
}
I am getting these images from ALAssetsLibrary as you can see above in the code. I am able to upload all the images successfully but the problem is that, it is consuming too much memory (see screenshot)
I am not able to release this memory even after uploading all the images or moving to different view. What am I suppose to do, which object do I've to release?
Thanks
Set up the cachePolicy of NSURLRequest to avoid cache, should be similar in ASIFormDataRequest
request.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData

What does ASIFileManagementError mean?

I am using ASI to download files and I keep seeing ASIFileManagementError. I am guessing that means that there is something wrong with how I'm building the download paths for my requests but it's not consistent. Sometimes the download works just fine and other times it fails. Even when using the same code on the same device to download the same file! Here is my code.
-(ASIHTTPRequest*)buildDownloadLinkForUpdate:(ContentItem*)update
{
NSString *URLString = [[NSString alloc] initWithFormat:#"%#?%#=%#", update.downloadUrl.absoluteString, #"auth_token", database.userAuthToken];
NSURL *url = [NSURL URLWithString:URLString];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setRequestMethod:#"GET"];
ContentItem* item = [database getItemWithId:update.uniqueId];
[request setDownloadDestinationPath:item.contentPath];
[request setTemporaryFileDownloadPath:[[AppSettings instance].temporaryPath stringByAppendingPathComponent:item.fileName]];
[request setAllowResumeForFileDownloads:TRUE];
[request setShowAccurateProgress: TRUE];
[request setDelegate:[_currentItem progressDelegate]];
return request;
}
-(void)initalizeNetworkQueue
{
if(!networkQueue) networkQueue = [[ASINetworkQueue alloc] init];
[networkQueue cancelAllOperations];
[networkQueue reset];
if([_currentItem progressDelegate])
{
[networkQueue setDownloadProgressDelegate:[_currentItem progressDelegate]];
}
[networkQueue setDelegate:self];
[networkQueue setRequestDidFinishSelector:#selector(networkQueueComplete:)];
[networkQueue setRequestDidFailSelector:#selector(networkQueueFailed:)];
[networkQueue setShowAccurateProgress:YES];
networkQueue.maxConcurrentOperationCount = 1;
}
And then here is the code that actually invokes this:
[self initalizeNetworkQueue];
[networkQueue addOperation:[self buildDownloadLinkForUpdate:_currentUpdate]];
[networkQueue go];
currentState = ContentUpdaterStateDownloading;
Is there something obviously wrong here?
-= UPDATE=-
It's saying that it's failing because it's unable to move the file from the temporary location to the final location.
Download Failed: Failed to move file from '/var/mobile/Applications/33E1DF3C-17F5-432F-8204-A9B53AB5AAE3/Documents/.temp/FileShare+Gate+4.pptx' to '/var/mobile/Applications/33E1DF3C-17F5-432F-8204-A9B53AB5AAE3/Documents/.content/FileShare+Gate+4.pptx'
I had this error before, it was in the connection, it is of type ASINetworkErrorType, it means that the host cannot be reached.
Anyway ASIHttprequest is dead now, you will not find answers for many questions you have, take my advice and go with AFNetworking, it is great and do the job.

asihttprequest Image download

Hello good morning everyone. I am using asihttprequest for a series of images download - 4 images from server.However i noticed an issues and cannot find a solution. Suppose i am downloading 4 images via URL and in case any one or 2 of the images is not available it cancels the whole queue.
Here is my code :
[networkQueue setDownloadProgressDelegate:progressIndicator];
[networkQueue setRequestDidFinishSelector:#selector(imageFetchComplete:)];
[networkQueue setRequestDidFailSelector:#selector(imageFetchFailed:)];
request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:#"http://imagees/image1.jpg"]];
[request setDownloadDestinationPath:[[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:#"1.png"]];
[request setDownloadProgressDelegate:imageProgressIndicator1];
[request setUserInfo:[NSDictionary dictionaryWithObject:#"request1" forKey:#"name"]];
[networkQueue addOperation:request];
request = [[[ASIHTTPRequest alloc] initWithURL:[NSURL URLWithString:#"sdvdsvsadvsadv"]] autorelease];
[request setDownloadDestinationPath:[[NSHomeDirectory() stringByAppendingPathComponent:#"Documents"] stringByAppendingPathComponent:#"2.png"]];
[request setDownloadProgressDelegate:imageProgressIndicator2];
[request setUserInfo:[NSDictionary dictionaryWithObject:#"request2" forKey:#"name"]];
[networkQueue addOperation:request];
- (void)imageFetchComplete:(ASIHTTPRequest *)request
{
UIImage *img = [UIImage imageWithContentsOfFile:[request downloadDestinationPath]];
if (img) {
if ([imageView1 image]) {
if ([imageView2 image]) {
[imageView3 setImage:img];
} else {
[imageView2 setImage:img];
}
} else {
[imageView1 setImage:img];
}
}
}
- (void)imageFetchFailed:(ASIHTTPRequest *)request
{
if (!failed) {
if ([[request error] domain] != NetworkRequestErrorDomain || [[request error] code] != ASIRequestCancelledErrorType) {
UIAlertView *alertView = [[[UIAlertView alloc] initWithTitle:#"Download failed" message:#"Failed to download images" delegate:nil cancelButtonTitle:#"OK" otherButtonTitles:nil] autorelease];
[alertView show];
}
failed = YES;
}
}
The problem is that suppose fetching second image failed, it displays the error message and stops the whole operation, although image 1 is a valid image file.
Any help will be greatly appreciated.
:)
From the ASIHTTPRequest documentation:
When a request in an ASINetworkQueue fails, the queue will by default
cancel all other requests. You can disable this behaviour with [queue
setShouldCancelAllRequestsOnFailure:NO].

How to remove the associated UIProgressview with the right request?

I use asihttprequest to download multiple files and I'm wondering how I can remove the associated UIProgressview with the right request when the download is done.
NSMutableArray *contentArray contains the ASIHTTPRequest and NSMutableArray *progArray contains my custom UIProgressview.
-(void)addDownload:(NSString *)theURL withName:(NSString *)fileName
{
theProgress = [[PDColoredProgressView alloc] initWithFrame:CGRectMake(3, 17, 314, 14)];
//...
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:theURL]];
//..
[request setDelegate:self];
[request setDownloadProgressDelegate:theProgress];
request.allowResumeForFileDownloads = YES;
[request startAsynchronous];
[request setShouldContinueWhenAppEntersBackground:YES];
[contentArray addObject:request];
[progArray addObject:theProgress];
[theProgress retain];
[self.tableView reloadData];
}
- (void)requestFinished:(ASIHTTPRequest *)request{
[contentArray removeObject:request];
[progArray removeObject:theProgress];
NSLog(#"%#",progArray);
NSLog(#"%#",contentArray);
[self reloadMyData];
[self.tableView reloadData];
}
The problem is that this code remove the last progressview even if the there are 3 downloads in contentArray and the second one finish first.
Can you help me with this ?
If you need to remove progress view that's associated with finished request you can get it from request's downloadProgressDelegate property:
- (void)requestFinished:(ASIHTTPRequest *)request{
PDColoredProgressView *progress = (PDColoredProgressView*)request.downloadProgressDelegate;
[contentArray removeObject:request];
if (progress)
[progArray removeObject:progress];
[self reloadMyData];
[self.tableView reloadData];
}

Resources