I am trying to download a file using AFNetworking (2.5.4). The download completes, the completion handler is called, with error set to nil, everything seeming fine, but the destination file does not exist:
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
NSString *fullPath = [valid path from my apps local manager]
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:req progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
return [NSURL URLWithString:fullPath];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
NSLog(#"Saved file to %#.", filePath);
*** [[NSFileManager defaultManager] fileExistsAtPath:filePath.absoluteString] returns NO here ***
}];
[cell.progressView setProgressWithDownloadProgressOfTask:downloadTask animated:YES];
[downloadTask resume];
The file path is a regular path that my app has write access to:
/var/mobile/Containers/Data/Application/APP-GUID-REDACTED/Documents/FILE-NAME-REDACTED.docx
I was using a different method before AFNetworking, and it could write to the exact same path just fine. HTTP response headers show everything perfectly (status 200, correct content length etc.) and if I curl the download URL it downloads the file with no issues. There's no problem with the file.
Why is my destination file not written in completion handler despite no errors?
UPDATE: I've also tried AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; but it changes nothing. I've also tried creating an NSProgress pointer and sending that for the progress argument, but no avail.
Use [NSURL fileURLWithPath:] (not URLWithString).
return [NSURL fileURLWithPath:fullPath];
The problem here is wrong file path or invalid file path. I had same problem here.
Create path like given below :
NSURL *documentsDirectoryURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
NSURL *filePathURL = [documentsDirectoryURL URLByAppendingPathComponent:[NSString stringWithFormat:#"your file name here",i]];
Now use above path :
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:req progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
return filePathURL;
}
Related
I am try to using AFnetworking to download a json file from my server.
And I following the official sample code.
After download the json, I need to use this json to do something with other local.
And I always get nil when I get this json file with my path.
Below is my code
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) {
if(!error){
NSLog(#"File downloaded to: %#", filePath);
if([[NSFileManager defaultManager] fileExistsAtPath:filePath.absoluteString]){
NSLog(#"file exists");
} else {
NSLog(#"file not exists");
}
}else{
NSLog(#"download error %#",error);
}
}];
[downloadTask resume];
And you see I add a logic to check the file exists or not.
Request always success but no file exist.
The file path will start with file:///var/...
How can I get back this json file?
Try using filePath.path instead of filePath.absoluteString when calling fileExistsAtPath
The FileManager needs to be passed a File URL
I'm using AFNetworking 3.0 to download a file, and it seems to be doing the downloading part fine, but I can't find the file afterwards.
I'm using the code below. In the download task, if I set breakpoints in the destination block, it seems as though the target path and download destination path are correct, and in fact at the point the targetPath points to a tmp file in the tmp folder which exists and contains the correctly downloaded data. However if I then hit a breakpoint in the completion handler block, the tmp file has disappeared and there is no file where my download destination path pointed.
Am I missing a step? Do I have to move this file myself, or is that something AFNetworking should be taking care of?
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
manager.responseSerializer = [AFHTTPResponseSerializer serializer];
self.theRequest = [[AFHTTPRequestSerializer serializer]
requestWithMethod:self.RequestMethod //#"POST"
URLString:requestURL.absoluteString //url to my API
parameters:self.Parameters //params being sent to API
error:nil];
//headers in this example:
//"Content-Type" = "application/json"
//"X-Requested-With" = XMLHttpRequest
//token = "<API TOKEN>";
for (id key in headers) {
[self.theRequest setValue:headers[key] forHTTPHeaderField:key];
}
self.theRequest.timeoutInterval = 60 * 100;
NSURLSessionDownloadTask * downloadTask =
[manager downloadTaskWithRequest:self.theRequest
progress:^(NSProgress * _Nonnull downloadProgress) {
if(self.DownloadProgressHandler)
self.DownloadProgressHandler(downloadProgress.fractionCompleted);
}
destination:^NSURL * _Nonnull(NSURL * _Nonnull targetPath, NSURLResponse * _Nonnull response) {
NSURL *url = [NSURL URLWithString:self.downloadDestinationPath];
NSLog(#"%#",[targetPath absoluteString]);
NSLog(#"%#",[url absoluteString]);
return url;
}
completionHandler:^(NSURLResponse * _Nonnull response, NSURL * _Nullable filePath, NSError * _Nullable error) {
[self RequestCompleteWithResponse:response responseObject:[[filePath absoluteString] dataUsingEncoding:NSUTF8StringEncoding] error:error];
}];
self.theTask = downloadTask;
[self.theTask resume];
Output from the NSLogs above:
2016-03-04 13:43:44.412 Marq[27505:154492] __23-[MarqAPI BuildRequest]_block_invoke247 line 648 $ file:///Users/aerion/Library/Developer/CoreSimulator/Devices/11594D0A-882C-4E46-9BAC-CEF7148014C7/data/Containers/Data/Application/E8C7D3EE-BB69-461F-BA2F-49EB7C2AE1CF/tmp/CFNetworkDownload_7VGArX.tmp
2016-03-04 13:43:44.425 Marq[27505:154492] __23-[MarqAPI BuildRequest]_block_invoke247 line 649 $ /Users/aerion/Library/Developer/CoreSimulator/Devices/11594D0A-882C-4E46-9BAC-CEF7148014C7/data/Containers/Data/Application/E8C7D3EE-BB69-461F-BA2F-49EB7C2AE1CF/Documents/9dfd86c2-458e-4725-a184-5fcd87f94dbd.inspect
Argh, that was silly of me. The answer is staring me in the face in those logs.
The file path for the temp file begins with file://, whereas my download destination path does not. the answer is to change
NSURL *url = [NSURL URLWithString:self.downloadDestinationPath];
to
NSURL *url = [NSURL fileURLWithPath:self.downloadDestinationPath];
This will give me a valid file path to send the downloaded file to
Idea
I'm building files download manager using AFNetworking and I'm using AFURLSessionManager class. the app is suppose to download mp3 files from the server.
I was concerned about memory consuming, so I'm trying to limit the number of simultaneous downloads to 1.
I know that there is a NSOperationQueue property in AFURLSessionManager called operationQueue and it's limited to 1 operation at a time by default.so I'm adding my NSURLSessionDownloadTask to operationQueue.
the problem
the code isn't working. files is being downloaded simultaneously instead of one after another.
the code
// 1. build sessionManager and prepare some vars
// note: by testing i found that it's better to init NSURLSessionConfiguration with backgroundSessionConfigurationWithIdentifier for memory issues
NSURLSessionConfiguration *conf = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:#"special_Identifier"];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:conf];
NSURL *urlDocs = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory
inDomain:NSUserDomainMask
appropriateForURL:nil
create:NO
error:nil];
__block NSProgress *progress = Nil;
// 2. open sessionManager operation Queue and add this new download
[manager.operationQueue addOperationWithBlock:^{
// 2.1 init new download request
NSURLRequest *request = [[NSURLRequest alloc]initWithURL:[NSURL URLWithString:fileLink]];
// 2.2 creat a NSURLSessionDownloadTask
NSURLSessionDownloadTask *downloadTask = [self.downloadManager downloadTaskWithRequest:request progress:&progress
destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
return [urlDocs URLByAppendingPathComponent:fileName];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
if (!error) {
NSLog(#"done: %#", filePath);
}else{
NSLog(#"error %#",error);
}
}];
// 2.3 start downloading
[downloadTask resume];
// 2.4 track downloading progress using KVO
[progress addObserver:self
forKeyPath:NSStringFromSelector(#selector(fractionCompleted))
options:NSKeyValueObservingOptionNew
context:(__bridge void *)(fileLink)];
}];
In AFNetworking 2 (and AFNetworking 3), you can init your AFHTTPSessionManager with an NSURLSessionConfiguration (use AFHTTPSessionManager initWithBaseURL:sessionConfiguration:). There you can specify the number of connections per host (HTTPMaximumConnectionsPerHost).
Sample:
NSURL *url = [NSURL URLWithString:#"myurl.net"];
NSURLSessionConfiguration *configuration = NSURLSessionConfiguration.defaultSessionConfiguration;
configuration.HTTPMaximumConnectionsPerHost = 1;
AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:url sessionConfiguration:sessionConfiguration];
Documentation:
AFHTTPSessionManager: http://cocoadocs.org/docsets/AFNetworking/3.0.4/Classes/AFHTTPSessionManager.html#//api/name/initWithBaseURL:sessionConfiguration:
NSURLSessionConfiguration: https://developer.apple.com/library/ios/documentation/Foundation/Reference/NSURLSessionConfiguration_class/#//apple_ref/occ/instp/NSURLSessionConfiguration/HTTPMaximumConnectionsPerHost
While working with the AFNetworking library I am running into an issue where after downloading JSON data into a file using the AFURLSessionManager downloadTaskWithRequest's destination param code block asynchronously, I am wanting to perform the remaining operations asynchronously as well in its completionHandler block. The problem is the completionHandler block does not seem to run asynchronously.
Would there be a need to setup a new session manager and/or download task to accomplish this. Is there perhaps a better way to do this so the operations can be performed away from the main thread in the completionHandler block.
The reason for wanting to accomplish this is to avoid tying up the main thread in case there's a huge amount of data which needs to be assigned to the self.googleResults array or rather in a for loop using a custom class containing properties for specific key data which would eventually be added as elements to an array.
Here's the code so far...
- (void)viewDidLoad
{
[super viewDidLoad];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]];
NSURL *url = [NSURL URLWithString:#"https://ajax.googleapis.com/ajax/services/search/web?v=1.0&q=json"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response)
{
// NOTE: This code block runs asynchronously
NSURL *docPathURL = [[NSFileManager defaultManager] URLForDirectory:NSDocumentDirectory inDomain:NSUserDomainMask appropriateForURL:nil create:NO error:nil];
return [docPathURL URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error)
{
// NOTE: This code block does not run asynchronously
// Would there be a need to create a new session and/or download task here to get the data from the filePath asynchronously?
// Or is there another way to this for the following code?
NSError *jsonSerializationErr;
NSData *jsonData = [NSData dataWithContentsOfURL:filePath];
NSDictionary *reponseDictionary = [NSJSONSerialization JSONObjectWithData:jsonData options:0 error:&jsonSerializationErr];
// self.googleResults is an instance of (NSArray *)
self.googleResults = [[reponseDictionary objectForKey:#"responseData"] objectForKey:#"results"];
NSLog(#"%#", self.googleResults);
}];
[downloadTask resume];
}
I need to download files from internet inside the app using internal web browser and save them to some custom path.
I think I should use UIWebViewDelegate and intercept lick clicks in
- (BOOL)webView:(UIWebView*)webView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType;
But here's my question: how can I know when the file is being downloaded (not just other webpage being opened).
I thought I could parse the link and determine if the extension is png, doc or something. But the problem is I need to be able to download the files of any type.
Thank you for any help.
UPDATE:
How can I recognize that this is link is actually for downloading. E.g. in this case -> etextlib.ru/Book/DownLoadPDFFile/19036 <- the link does not have recognizable extension.
You only have two ways to go about this in my opinion, and both involve implementing shouldStartLoadWithRequest:
Define which file types you want to download and check for them in the tapped link.
On any tap the user makes on a link, do the following
If the link is to a known file type, download it.
If the link is a web page (htm, html, asp, ...), just open it
Any other case: Ask user whether he wants to download the link as a file.
AFNetworking
Creating a Download Task
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
NSURL *URL = [NSURL URLWithString:#"http://example.com/download.zip"];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
NSURLSessionDownloadTask *downloadTask = [manager downloadTaskWithRequest:request progress:nil destination:^NSURL *(NSURL *targetPath, NSURLResponse *response) {
NSURL *documentsDirectoryPath = [NSURL fileURLWithPath:[NSSearchPathForDirectorie
sInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]];
return [documentsDirectoryPath URLByAppendingPathComponent:[response suggestedFilename]];
} completionHandler:^(NSURLResponse *response, NSURL *filePath, NSError *error) {
NSLog(#"File downloaded to: %#", filePath);
}];
[downloadTask resume];
just check [request.URL.absoluteString pathExtension] to see the type of link and do what you want