iOS - AFNetworking resume download after fail - ios

I am downloading a file with AFNetworking using an AFHTTPRequestOperation.
I want the user to be able to resume the download after it fails (from either a time out, or a lost connection...).
How would I do this?
I have read that AFDownloadRequestOperation does this, but this is not officially part of AFNetworking, and it is not up to date.
How do I resume a failed download?

So I was able to resume by doing this:
First I make my app remember the "totalBytesRead" and "totalBytesExpectedToRead".
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {...}
Then, when the download fails, I have a retry button. When the user clicks the button, I call this code
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:#"www.myfileURL.com/file.mp4" cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:10];
NSString* range = [NSString stringWithFormat:#"bytes=%lli-%lli", totalBytesRead, totalBytesExpectedToRead];
[request setValue:range forHTTPHeaderField:#"Range"];
operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:myPath append:YES];
Make sure you properly set the http header for range in the format "bytes=fromBytes-totalBytes". An example would be "bytes=3200-12000"
Make sure that when you make the new operation, you change the output stream to APPEND:YES. This is so your downloaded bytes append to the previously downloaded ones.

Related

ResumeData getting nil when using downloadTaskWithRequest

If I'm using this below code
aDownloadTask = [self.backgroundSession downloadTaskWithURL:aRemoteURL];
Desc of above code:
When I started download by using downloadTaskWithURL It’s return expectedContentLength negative(-1) But that time resume data getting perfectly.
Another one is
For solved above problem I'm using this below code
NSMutableURLRequest *aURLRequest = nil;
aURLRequest = [[NSMutableURLRequest alloc] initWithURL:aRemoteURL cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:60.0];
[aURLRequest setHTTPMethod:#"POST"];
[aURLRequest setValue:#"identity" forHTTPHeaderField:#"Accept-Encoding"];
aDownloadTask=[self.backgroundSession downloadTaskWithRequest:aURLRequest];
Desc of above code: Using above code expectedContentLength getting perfectly. But issue is the when pause downloading resume data nil every time.
Thats why my downloading start from beginning and not from that point when I pause.
Thanks in advance
Please , remove this below line from your code and try. Your resume data will getting perfectly.
[aURLRequest setHTTPMethod:#"POST"];

Updating files in iOS app

I have .json file in my Xcode project that contains much information.
I can't fetch it each time because it's really big. But I'd like to update that file once a week in my app. Is it possible?
Maybe you can make a local notification that is fired once a week, and then download the file. Or you can even send push notifications to tell the app to download.
To download a file (in this case and unzip it using SSZipArchiver and AFNetworking for the download):
NSString *url = [NSString stringWithFormat:#"someurl"];
NSString *directoryPath = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];
NSString *filePath = [directoryPath stringByAppendingPathComponent:[NSString stringWithFormat:#"nameofthefile.zip"]];
zipPath = filePath;
NSLog(#"DIRECTORY WHERE THE FILES ARE SAVED-->%#",directoryPath);
AFURLConnectionOperation *operation1 = [[AFHTTPRequestOperation alloc] initWithRequest:request];
operation1.outputStream = [NSOutputStream outputStreamToFileAtPath:filePath append:NO];
[operation1 setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead)
{
NSLog(#"-----> %f", (float)totalBytesRead / totalBytesExpectedToRead);
self.hud.progress = (float)totalBytesRead / totalBytesExpectedToRead;
}];
[operation1 setCompletionBlock:^()
{
[SSZipArchive unzipFileAtPath:zipPath toDestination:directoryPath overwrite:YES password:nil error:nil delegate:self];
}];
[operation1 start];
Here is some information: How to create local notifications Stackoverflow
You cannot replace the file in your Xcode project. You can only read resources from the application bundle. If you want to write you need to first copy the file to the application documents directory and modify it there.
Now you can download even large files in the background and replace the file in the writable directory when you are done.
Further remarks:
Think about how you could devise the web service to just send incremental changes. That seems so much more reasonable. Also, rather than parsing the content of a huge JSON file into memory, you might be better off using Core Data.

How to improve the speed while using NSURLSessionDownloadTask?

I need to download some images and a video from server:
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
AFURLSessionManager *manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration];
for (int i = 0; i < _collectionArr.count; ++i) {
NSURL *URL = [NSURL URLWithString:URL_ADDRESS(portNumber,_collectionArr[i])];
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);
if (i == _collectionArr.count - 1) {
[SVProgressHUD showSuccessWithStatus:#"Done"];
}
}];
[downloadTask resume];
}
I found that it is so slow! The speed is about 200K/s and the time with Android is 2/3 less than iPhone.
When I download a mp4 about 4.6M, it takes 15s.
2014-11-29 13:46:35.071 testDownload[2105:47825] Begin
2014-11-29 13:46:51.740 testDownload[2105:47825] File downloaded to: file:///Users/apple/Library/Developer/CoreSimulator/Devices/259F2CB8-01FD-47C2-A38F-6100A2FF350A/data/Containers/Data/Application/71E553BC-F85D-4BFA-8937-FE9026FDF65C/Documents/VTS_01_audi.mp4
But when I using other app to download movies it can be 2M/s. Am I wrong when I use afnetworking ? How it happens and what can I do to deal with it.
Another question is that I know it's wrong to monitor the last request with if (i == _collectionArr.count - 1){[SVProgressHUD showSuccessWithStatus:#"Done"];} But I don't know the right answer.
Thanks for your help.
A couple of thoughts:
The removal of the HUD when i hits count - 1 is not correct. You actually may remove it before they're all done. If you start two downloads, one huge one and one tiny one, the HUD will be dismissed when the second one finishes, but the other one might not be done yet. These run concurrently, so you have to wait until they're all done, not just when the last submitted one is done.
One way to do this is to use a dispatch group (which you enter as you submit the requests, leave in the completion block, and then add a dispatch group notification that removes the HUD).
You're not doing anything else outside of this code that might be blocking the main thread are you? AFNetworking dispatches its completion blocks to the main queue, and if you block the main thread for anything, it will affect this performance. You could either use Instruments to identify waiting threads, or, for testing purposes only, temporarily change the completionQueue of the manager to be some custom queue of your own creation.
For example, before your for loop, do something like:
manager.completionQueue = dispatch_queue_create("com.example.app.netCompletionQueue", NULL);
That would take main thread blocking out of the equation (though this strikes me as unlikely unless you're doing something extraordinary in the main thread). Once you confirm this is not the issue, though, comment out that line, because you really do want to use the main thread for your completion blocks.
Once you confirm the perf problem is not result on main thread contention issue, I'd suggest doing some benchmarking of alternative techniques (e.g. your own NSURLSession, etc.). This could help diagnose whether the problem is AFNetworking, rather than something like simulator vs device performance, caching, etc. Frankly, I find it unlikely that AFNetworking is, itself, the problem, though.

AFNetworking download progress issue iOS

I am using following code in order to download zip file using following code with only one running operation at a time
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:TempUrl]];
operation = [[AFHTTPRequestOperation alloc] initWithRequest:request];
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *path = [[paths objectAtIndex:0] stringByAppendingPathComponent:[NSString stringWithFormat:#"%#.zip",model.iD]];
operation.outputStream = [NSOutputStream outputStreamToFileAtPath:path append:NO];
[operation setUserInfo:[NSDictionary dictionaryWithObject:model forKey:#"model"]];
[operation setDownloadProgressBlock:^(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead) {
NSLog(#"%lu",(unsigned long)bytesRead);
NSLog(#"%lu",(unsigned long)totalBytesRead);
NSLog(#"%lu",(unsigned long)totalBytesExpectedToRead);
}];
Following code handles pausing and resuming download on app home button press or screen lock
// Notification invokes these methods
-(void)appEntersBg { // Application enters background
if([[self downloadQueue] operationCount]) {
[[[[self downloadQueue]operations]firstObject] pause];
}}
-(void)appEntersForground { // application enters forground
if([[self downloadQueue] operationCount]) {
[[[[self downloadQueue]operations]firstObject] resume];
}
}
When I start a download i get proper values in bytes read and bytes expected
but weird values when app enters Background and then again enters forground.
Like I am downloading a file of size 10MB
I start download and DOWNLOADEDSIZE reaches 4MB.
and EXPECTEDDOWNLOADSIZE size is 10MB
Now I press home button and downloading PAUSES.
Launch app
App Enters Forground and downloading RESUMES
Now EXPECTEDDOWNLOADSIZE is 6MB (10-4MB)
and DOWNLOADEDSIZE is same as previous 4MB.
File is downloaded properly but How will I show the download progress correctly after
multiple times app getting into background and foreground
Any suggestions or help
I am working on iOS 7 and AFNetworking 2.

asihttprequest download file, But shutdown when screen lock

I use IOS7
I start download and i lock screen, and i open screen. My program is shutdown...
Is there some can help me ?
This is major code:
init download url:
NSURL *url = [NSURL URLWithString:dictionaryUrl];
ASIHTTPRequest *request = [[ASIHTTPRequest alloc] initWithURL:url];
set ASIHTTPRequest delegate:
request.delegate = self;
init file save path:
NSString *savePath = [path stringByAppendingPathComponent:name];
bool b=[ fileManager createFileAtPath :savePath contents : nil attributes : nil ];
if (b){
fileHandle=[ NSFileHandle fileHandleForWritingAtPath :savePath];
}
[request setAllowResumeForFileDownloads:NO];
[request setDelegate:self];
[request setDidFinishSelector:#selector(requestDone:)];
[request setDidFailSelector:#selector(requestWentWrong:)];
[request setDataReceivedBlock :^( NSData * data){
[fileHandle seekToEndOfFile ];
[fileHandle writeData :data];
[ label setText :[ NSString stringWithFormat : #"downloading...%.1f %%" , process . progress * 100 ]];
}];
[request setDownloadProgressDelegate:process];
add to ASINetworkQueue:
[self.netWorkQueue addOperation:request];
relase request:
[request release];
First, you need to enable the request to run at background. add this :
[request setShouldContinueWhenAppEntersBackground:YES];
for quick task it's possible, works like charm. but for long running task, just like you wanted, to keep continue download, you need to add a bit code, to enable this request from being terminated because run too long.
I've answered question for location update by adding timer and fire API every x seconds indefinitely. using UIBackgroundTaskIdentifier and NSTimer. This should give you an idea. should be same concept of what you are doing.
How do I get a background location update every n minutes in my iOS application?
When your screen gets lock your app goes to background.You can perform tasks for a limited time after your application is directed to go to the background, but only for the duration provided. Running for longer than this will cause your application to be terminated. See the "Completing a Long-Running Task in the Background" section of the iOS Application Programming Guide for how to go about this.
For iOS7 you can check this link https://stackoverflow.com/a/19355437/1372368.
And the code snippet to run task in background you can find various links like:How to keep an iPhone app running on background fully operational

Resources