I have trying to download the multiple .mp3 files from a server at time. One complete audio file is divided into 286 parts. I fetch all the urls of the file and now I want to download 286 files. I search a lot but many library stop downloading when I go back to previous controller and if user minimize the app the downloaded stop. Is there any library which can manage multiple downloads and download didn't stop when user go back to previous controller of minimize the app.
I am using Download Manager library but I can't get my desired. Please give me the solution. I am stuck with that from 3 days . Please tell me the solution . Thanks
In my project I'm using AFNetwirking. You can create a singleton object, and here is my method (for example) for downloading files :
- (AFHTTPRequestOperation *)performDownloadWithURLString:(nonnull NSString *)urlString
destinationPath:(NSString *)destinationPath
progress:(void (^)(long long bytesRead, long long totalBytesToRead))progress
apiCallback:(void(^)(BOOL isSuccessful, id object))apiCallback
{
NSURL *url = [NSURL URLWithString:urlString];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
NSString *fullPath = [[FCFileManager pathForTemporaryDirectory] stringByAppendingPathComponent:[url lastPathComponent]];
[operation setOutputStream:[NSOutputStream outputStreamToFileAtPath:fullPath append:NO]];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead)
{
if(progress) {
progress(totalBytesRead, totalBytesExpectedToRead);
}
}];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if(destinationPath && [FCFileManager isFileItemAtPath:destinationPath]) {
NSError *removeError;
[FCFileManager removeItemAtPath:destinationPath error:&removeError];
}
if(destinationPath) {
[FCFileManager moveItemAtPath:fullPath toPath:destinationPath];
}
dispatch_async(dispatch_get_main_queue(), ^{
if(apiCallback) {
apiCallback(YES, destinationPath ?: fullPath);
}
});
});
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSError *removeError;
[FCFileManager removeItemAtPath:fullPath error:&removeError];
if(apiCallback) {
apiCallback(NO, [AZError errorWithNSError:error]);
}
}];
[operation start];
}
Hope it helps you.
Related
I'm using AFNetworking to download more or less 200 images. The problem is that the main thread is blocked during the download, not during the success/failure block.
Here is my code:
imageDownloads=[[NSMutableArray alloc]init];
for(NSString *url in liens){
NSString *totalURL = [NSString stringWithFormat:#"http://%#", url];
[imageDownloads addObject:[[ImageDownload alloc] initWithURL:[NSURL URLWithString:totalURL] filename:nil]];
}
for (int i=0; i < imageDownloads.count; i++)
{
ImageDownload *imageDownload = imageDownloads[i];
[self downloadImageFromURL:imageDownload];
}
- (void)downloadImageFromURL:(ImageDownload *)imageDownload
{
NSURLRequest *request = [NSURLRequest requestWithURL:imageDownload.url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
imageDownload.totalBytesRead = totalBytesRead;
imageDownload.totalBytesExpected = totalBytesExpectedToRead;
[self updateProgressView];
}];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSAssert([responseObject isKindOfClass:[NSData class]], #"expected NSData");
imageDownload.totalBytesExpected = imageDownload.totalBytesRead;
[self updateProgressView];
//all kind of basic stuff here I left out: I get store the data inside CoreData
NSLog(#"finished %#", imageDownload);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"error %#", error);
}];
[operation start];
}
Basically, when I launch the code, the thread is blocked for like 30-40 seconds (the pictures are about 100MB in total), and then suddenly I can see all the NSLog logs appear with the "Finished"... text. So that part if really quick. But I thought AFNetworking wasn't supposed to block the main thread while I was downloading? This also doesn't allow me to track the progress of the download...Am I doing something wrong or misinterpreting something?
You're updating the progress view in the progress block. Because AFNetworking is inherently async anyway, each of these requests will stack and run at the same time. If you're running 200 of them, that's going to freeze up the app. Try using NSOperationQueue's maxConcurrentOperationCount to limit the number of concurrent threads.
Alternatively, you could save all the trouble and just use sdwebimage.
I would like to download a folder which consists several kind of files(png,jpg,mov,txt and pdf). I am using AFNetworking. I have used below code for downloading,
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[Utilities urlencode:imageURL]]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:str_path append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject)
{
//NSLog(#"Successfully downloaded file to %#", str_path);
}
failure:^(AFHTTPRequestOperation *operation, NSError *error)
{
NSLog(#"Error: %# =====%# =======%#", error.localizedDescription,str_path,imageURL);
}];
[operation setDownloadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToRead)
{
float progress = totalBytesWritten / (float)totalBytesExpectedToRead;
NSLog(#"Download Percentage: %f %%", progress*100);
}];
[operation start];
The above code works fine for individual files. But i have got error code of 21 while downloading folder. Any help would be greatly appreciated.
HTTP does not support downloading multiple files in one request. This is pretty much the same question asked here in reverse.
If you have FTP access you can use the CFFTP API to download the contents of a directory.
I am using AFNetworking Library,
How to download the large amount of data using AFNetworking Library to show the better performance?
I have followed the following steps:
".zip" files downloading the content from server.
I have added one url , like this i have so many url's to download the content from the server. It takes too much time. How to perform the fast downloading from server.
My Query is: If the url was not found on server, then it executes failure state.
but the ".zip" is storing in documents folder with empty content like zerobytes.
while am trying to extract the .zip it shows .cpgz format.
Let us know how to resolve this?
-(void)downloadSingFile:(NSUInteger )activityAtIndex totalCount:(NSUInteger )lessonTotalCount{
// http://118.102.131.158/IYG_wrapper/IYG_updated/IYG_G7_L03/IYG_UN_Mall.zip
NSString *activityUrl = [filterObjects objectAtIndex:activityAtIndex];
NSURL *zipFileAtUrl = [NSURL URLWithString:[activityUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
BOOL success = [libraryObj createFolderWithName:rootName];
if (success) {
activityPath = [[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:rootName] stringByAppendingPathComponent:[zipFileAtUrl lastPathComponent]];
}
NSURLRequest *request = [NSURLRequest requestWithURL:zipFileAtUrl];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:activityPath append:NO];
[operation setCompletionBlock:^{
sleep(1);
NSLog(#"sucessfully downloaded file %d",activityIndx);
[self extractSingleActivityAtindex:activityIndx];
}];
[operation start];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
float percentDone = ((float)(totalBytesRead) / (float)(totalBytesExpectedToRead));
self.tableView.alpha = 0.7;
progressView.hidden = NO;
progressAlert.hidden = NO;
progressAlert.labelText = #"Downloading..";
[self updateProgress:percentDone];
NSLog(#"progress float value is: %.2f",percentDone);
}];
}
1.Please let us know, now i dont want to download the which is exist in documents folder path and also let us know whether the the file has been downloaded sucessfully or not.
A couple of thoughts:
If you want to know if it succeeded or not, rather than using setCompletionBlock, you should use setCompletionBlockWithSuccess:failure:.
In a related topic, I might be inclined to download the file to some temporary file (in the NSTemporaryDirectory() folder) and only once it was successfully downloaded, move it to the Documents folder. You want to completely eliminate the possibility of any in-progress download resulting in a file in Documents.
If you don't want to download a file that already exists in your Documents folder, then you have to program that logic yourself (i.e. use NSFileManager to see if the file exists, and if not, only then initiate the download).
Eliminate the sleep call. You never want to sleep (esp on the main thread). If you really want to trigger something to happen one second later, use dispatch_after:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
NSLog(#"sucessfully downloaded file %d",activityIndx);
[self extractSingleActivityAtindex:activityIndx];
});
You need to take care of below points to achieve your functionality
Check file is already exist or not before download
Implement failure block and remove file at your activityPath
For reference, please check below code snippet.
-(void)downloadSingFile:(NSUInteger )activityAtIndex totalCount:(NSUInteger )lessonTotalCount{
// http://118.102.131.158/IYG_wrapper/IYG_updated/IYG_G7_L03/IYG_UN_Mall.zip
NSString *activityUrl = [filterObjects objectAtIndex:activityAtIndex];
NSURL *zipFileAtUrl = [NSURL URLWithString:[activityUrl stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
BOOL success = [libraryObj createFolderWithName:rootName];
if (success) {
activityPath = [[[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:rootName] stringByAppendingPathComponent:[zipFileAtUrl lastPathComponent]];
}
if ([[NSFileManager defaultManager]fileExistsAtPath:activityPath]) {
NSLog(#"File Already Exist");
[self extractSingleActivityAtindex:activityIndx];
return;
}
NSURLRequest *request = [NSURLRequest requestWithURL:zipFileAtUrl];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:activityPath append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
sleep(1);
NSLog(#"sucessfully downloaded file %d",activityIndx);
dispatch_async(dispatch_get_main_queue(), ^() {
[self extractSingleActivityAtindex:activityIndx];
});
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
// NSLog(#"ERR: %#", [error description]);
[[NSFileManager defaultManager]removeItemAtPath:activityPath error:nil];
}];
[operation start];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
float percentDone = ((float)(totalBytesRead) / (float)(totalBytesExpectedToRead));
self.tableView.alpha = 0.7;
progressView.hidden = NO;
progressAlert.hidden = NO;
progressAlert.labelText = #"Downloading..";
[self updateProgress:percentDone];
NSLog(#"progress float value is: %.2f",percentDone);
}];
}
I'm trying to figure out a way to download multiple images with AFNewtorking 2.0. I've read a lot of posts here in SO, but can't find the answer I'm looking for, hope you guys can help me.
The problem is that I want to know when all of the downloads finished and if all images where downloaded.
So I have an array with image URL's ant trying to do something like this.
for(NSString *photoUrlString in self.photos){
NSURL *url = [NSURL URLWithString:photoUrlString];
AFHTTPRequestOperation *requestOperation = [[AFHTTPRequestOperation alloc] initWithRequest:[NSURLRequest requestWithURL:url]];
requestOperation.responseSerializer = [AFImageResponseSerializer serializer];
[requestOperation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Image error: %#", error);
}];
[requestOperation start];
}
I've found some answers with putting these requests into a queue and setting max concurrent operations to 1. But don't know how that works really.
Any help is appreciated, thanks in advance!
for(Photo *photo in array){
//form the path where you want to save your downloaded image to
NSString *constPath = [photo imageFullPath];
//url of your photo
NSURL *url = [NSURL URLWithString:photo.serverPath];
AFHTTPRequestOperation *op = [[AFHTTPRequestOperation alloc] initWithRequest:[NSURLRequest requestWithURL:url]];
op.responseSerializer = [AFImageResponseSerializer serializer];
op.outputStream = [NSOutputStream outputStreamToFileAtPath:constPath append:NO];
op.queuePriority = NSOperationQueuePriorityLow;
[op setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead){
}];
op.completionBlock = ^{
//do whatever you want with the downloaded photo, it is stored in the path you create in constPath
};
[requestArray addObject:op];
}
NSArray *batches = [AFURLConnectionOperation batchOfRequestOperations:requestArray progressBlock:^(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations) {
} completionBlock:^(NSArray *operations) {
//after all operations are completed this block is called
if (successBlock)
successBlock();
}];
[[NSOperationQueue mainQueue] addOperations:batches waitUntilFinished:NO];
Try this:
// _group, _queue are iVar variable
dispatch_group_t *_group = dispatch_group_create();
dispatch_queue_t *_queue = dispatch_queue_create("com.company.myqueue2", NULL);
// all files download
for(int i = 0 ; i < numberOfFileDownloads; i++){
dispatch_group_async(_group, _queue, ^{
// here is background thread;
// download file
});
}
// all files are download successfully, this method is called
dispatch_group_notify(_group, _queue, ^{
}
Check out +[AFURLConnectionOperation batchOfRequestOperations:progressBlock:completionBlock:]
Although it's not documented, implementation is self-explanatory. Also it allows you to monitor the progress.
You will need to have an array of HTTP operations prior to using this method (this is if you decided to stick to NSURLConnection-based implementation of AFNetworking).
I am new to web services and I have searched it but I couldn't find any documents about it. Is there any way to download images and videos from WCF Service and save the my app's document files? or do I need to use different way for download?
Thanks for your advice and interest.
Try using AFNetWorking: https://github.com/AFNetworking/AFNetworking
This is a sample how I download files from a WCF:
NSMutableURLRequest *reqeust = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:{url}]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:reqeust];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:{path_on_disk} append:NO];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
//Download progress
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//Download failed
}];
[operation start]