Downloading File using AFHTTPRequest Operating isn't working? - objective-c

This is the code I'm using (from this Stack Overflow question, although it's slightly modified):
NSLog(#"Saving File...");
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[detailDataSourceDict valueForKey:#"filepath"]]];
NSLog(#"This is the link you are downloading: %#",request);
AFHTTPRequestOperation *operation = [[[AFHTTPRequestOperation alloc] initWithRequest:request] autorelease];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Successfully downloaded file to %#", path);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
I get the NSLog "Successfully downloaded file to /Users/xxxx/Library/Application Support/iPhone Simulator/6.0/Applications/F29C1E99-A277-41DC-8205-6556B6123A85/Documents" but when I open up that folder in Finder, I don't see the file. Is there anything that I am doing wrong? I am not getting errors in my code. Any help would be appreciated, thanks.
Update
I am using the AFNetwork library...

You're setting the download location to the actual Documents Directory, rather than a file in the directory. Update your code to use a specific file within the directory.
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [paths objectAtIndex:0]; //filepath to documents directory!
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:[path stringByAppendingPathComponent:#"filename.extension"] append:NO];
Also, I think you may want to be setting the inputStream property rather than the outputStream because you are downloading a file rather that uploading one.

Related

xcode & (un)zip file

I have an problem, I have develop one app where I actually need to unzip file. This files I receive from internet, save on Document folder of device and try to unzip.
But... unzip never occurs. The message I receive is:
Error Domain=SSZipArchiveErrorDomain Code=-1 "failed to open zip file" UserInfo=0xad36430 {NSLocalizedDescription=failed to open zip file}
Also I tried other library... but the result is the same.
The zip file is made by server (so we have no control over this part.) but we know that they use gzip to create this file.
I have already used "search"... but with no luck.
One more important note. If I unzip this file on my mac, than zip it again and point "localFilePath" to this new file, all works fine!. Also, the server guy say that they use this ZIP in other apps with no problems at all.
Any advice where do I need to look?
Thanks
The code:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:#"http://......"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
return [documentsDirectoryURL URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
NSLog(#"File downloaded to: %#", filePath);
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *localFilePath = [[paths objectAtIndex:0] stringByAppendingPathComponent:[filePath lastPathComponent]];
NSString *unzipFolder = [[paths objectAtIndex:0] stringByAppendingPathComponent:#"/unzipfolder"];
NSLog(#"localFilePath: %#",localFilePath);
NSLog(#"unzip folder: %#",unzipFolder);
NSError *erro = nil;
[SSZipArchive unzipFileAtPath:localFilePath toDestination:unzipFolder overwrite:YES password:nil error:&erro delegate:self];
NSLog(#"Erro: %#",erro);
}];
[downloadTask resume];

Using AFnetworking to save mp4

I've been using AFnetworking to download a video from a remote server. It works great except for the fact it downloads the file as data rather than the original format (in this case mp4).
Is there a way to set AFnetworking to download the file as an mp4? when it comes to playback it seems like a waste of time and resources to convert the data file back into mp4 each time the video is played.
My current code for gaining the file is below:
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:[URL url]]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
initWithRequest:request];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:[URL title]];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Successfully downloaded file to %#", path);
URL.videolocal = #"YES";
[self saveToCoreData]; // video is not saved in core data, only a reference
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
If the data coming from the server is already in MP4 format, then just name the file with a .mp4 suffix.

Renaming an existing file with Obj-C

I've seen this question asked a few times but I have been unable thus far to achieve success using any of the post solutions. What I am trying to do is rename a file in the local storage of an app (also kind of new to Obj-c). I am able to retrieve the old path and create the new path, but what would I have to write in order to actually change the files name?
What I have thus far is:
- (void) setPDFName:(NSString*)name{
NSArray *dirPaths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES);
NSString* initPath = [NSString stringWithFormat:#"%#/%#",[dirPaths objectAtIndex:0], #"newPDF.pdf"];
NSString *newPath = [[NSString stringWithFormat:#"%#/%#",
[initPath stringByDeletingLastPathComponent], name]
stringByAppendingPathExtension:[initPath pathExtension]];
}
NSError *error = nil;
[[NSFileManager defaultManager] moveItemAtPath:initPath toPath:newPath error:&error];
The code is very messy; try this:
- (BOOL)renameFileFrom:(NSString*)oldName to:(NSString *)newName
{
NSString *documentDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,
NSUserDomainMask, YES) objectAtIndex:0];
NSString *oldPath = [documentDir stringByAppendingPathComponent:oldName];
NSString *newPath = [documentDir stringByAppendingPathComponent:newName];
NSFileManager *fileMan = [NSFileManager defaultManager];
NSError *error = nil;
if (![fileMan moveItemAtPath:oldPath toPath:newPath error:&error])
{
NSLog(#"Failed to move '%#' to '%#': %#", oldPath, newPath, [error localizedDescription]);
return NO;
}
return YES;
}
and call this using:
if (![self renameFileFrom:#"oldName.pdf" to:#"newName.pdf])
{
// Something went wrong
}
Better still, put the renameFileFrom:to: method into a utility class and make it a class method so it can be called from anywhere in your project.

AFNetworking + queue + cancel operations + junk files

i 'm downloading some files using AFNetworking using a queue. Here is my code:
apiClient =[[AFHTTPClient alloc]initWithBaseURL: [NSURL URLWithString:ZFREMOTEHOST]];
for (NSString *element in self.productsArray) {
NSURL *url = [NSURL URLWithString:element];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
op = [[AFHTTPRequestOperation alloc] initWithRequest:request];
NSString *documentsDirectory = nil;
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
documentsDirectory = [paths objectAtIndex:0];
NSString *targetFilename = [url lastPathComponent];
NSString *targetPath = [documentsDirectory stringByAppendingPathComponent:targetFilename];
op.outputStream = [NSOutputStream outputStreamToFileAtPath:targetPath append:NO];
[op setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
//failure case
NSLog(#"BaaZ File NOT Saved %#", targetPath);
//remove the file if saved a part of it!
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:targetPath error:&error];
if (error) {
NSLog(#"error dude");
}
if ([operation isCancelled]) {
//that doesn't work.
NSLog(#"Canceled");
}
}];
[op setDownloadProgressBlock:^(NSInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
if (totalBytesExpectedToRead > 0) {
dispatch_async(dispatch_get_main_queue(), ^{
self.progressView.alpha = 1;
self.progressView.progress = (float)totalBytesRead / (float)totalBytesExpectedToRead;
NSString *label = [NSString stringWithFormat:#"Downloaded %lld of %lld bytes", totalBytesRead,totalBytesExpectedToRead];
self.progressLabel.text = label;
});
}
}];
[self.resourcesArray addObject:op];
}
for (AFHTTPRequestOperation *zabols in self.resourcesArray) {
[apiClient.operationQueue addOperation:zabols];
}
the code is working fine on file downloading but i want some cancel functionality so i have a button with an action that has the code below:
[apiClient.operationQueue cancelAllOperations];
the operations cancel file but then there are some junk files on the Documents folder. By saying junk i mean file that started downloading i canceled them and the i get a file with the same name but useless can't be opened cause it's damaged.
How can i prevent AF from doing that and keep only the completed files when i cancel it?
any help would be grateful.
Also tried canceling job by job like that:
for (AFHTTPRequestOperation *ap in apiClient.operationQueue.operations) {
[ap cancel];
NSLog(#"%#",ap.responseFilePath);
NSFileManager *fileManager = [NSFileManager defaultManager];
[fileManager removeItemAtPath:ap.responseFilePath error:nil];
}
and deleting the junk files but that doesn't work either.
Try using AFDownloadRequestOperation extension, it additionally supports resume a partial download, uses a temporary directory and has a special block that helps with calculating the correct download progress.
You can also try that : github

AFnetworking downloading multiple files

I'm using this code to loop through an array to download multiple files and write to disk.
-(void)download
{
//set url paths
for (NSString *filename in syncArray)
{
NSString *urlpath = [NSString stringWithFormat:#"http://foo.bar/photos/%#", filename];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:urlpath]];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:filename];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Successfully downloaded file to %#", path);
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
NSLog(#"Error: %#", error);
}];
[operation start];
but the problem is it calls the success block after each file is done, (which it should) but I just need one final call back to reload some data and end a progress HUD.
Any pointers in the right direction would be great.
Maybe someday this will help someone, but I was able to use a workaround that probably has major issues but its okay for my simple usage.
I just deleted each line from the sync array after it was processed then ran my code i needed.
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
NSLog(#"Successfully downloaded file to %#", path);
[SVProgressHUD showWithStatus:#"Updating Photos"];
[syncArray removeObject:filename];
if (!syncArray || !syncArray.count)
{
NSLog(#"array empty");
[[NSNotificationCenter defaultCenter] postNotificationName:#"TestNotification" object:self];
[SVProgressHUD dismissWithSuccess:#"Photos Updated"];
}
You can use AFHTTPClient to enqueueBatchOperations and this has a completionBlock which is called when all operations are finished. Should be exactly what you're looking for.