I got this code to implement something which helps me downloading a file from a given URL.
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
NSLog(#"Temporary File :%#\n", location);
NSError *err = nil;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSURL *docsDirURL = [NSURL fileURLWithPath:[docsDir stringByAppendingPathComponent:#"out1.zip"]];
if ([fileManager moveItemAtURL:location
toURL:docsDirURL
error: &err])
{
NSLog(#"File is saved to =%#",docsDir);
}
else
{
NSLog(#"failed to move: %#",[err userInfo]);
}
}
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
//You can get progress here
NSLog(#"Received: %lld bytes (Downloaded: %lld bytes) Expected: %lld bytes.\n",
bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
}
Second part:
-(void) downloadFileWithProgress
{
NSURL * url = [NSURL URLWithString:#"https://s3.amazonaws.com/hayageek/downloads/SimpleBackgroundFetch.zip"];
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];
NSURLSessionDownloadTask * downloadTask =[ defaultSession downloadTaskWithURL:url];
[downloadTask resume];
}
All of this code is in my Download.m
My download.h is:
#interface Download : NSObject
-(void) downloadFileWithProgress
#end
I really dont know how to get the download starting. In another class I created a button which should start the download:
-(IBAction)buttonStartDownload:(id)sender {
[Download downloadFileWithProgress];
}
The error is in the last line:
No known class method for selector 'downloadFileWithProgress'
But why?
The method '-(void) downloadFileWithProgress' is an instance method so you cant call this method by using class name 'Download'.
In order to call this method you need to create an instance of 'Download' class and call the method on that instance.
Method -(void)downloadFilwWithProgress in instance method...So to call that method
-(IBAction)buttonStartDownload:(id)sender {
Download *downldObj=[[Download alloc]init];
[downldObj downloadFileWithProgress];
}
If you write method +(void)downloadFilwWithProgress then you can call like this.[Download downloadFileWithProgress]
Related
I am developing an app where I need to download a video and then perform some editing on it.So, I am downloading a video using NSURLSession and when I Have downloaded it,I close the app and then open it again.Now instead of using that downloaded video,I need to check if its already downloaded and then get the URL.Here is the code that I have been using:
-(void)startDownloadingWithURLString:(NSString*)urlString{
NSURL *url = [NSURL URLWithString:urlString];
configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
self.urlSession = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:[NSOperationQueue mainQueue]];
task = [self.urlSession downloadTaskWithURL:url];
[task resume];
}
#pragma mark - NSURLSession delagate methods
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
NSString *path = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSFileManager *fileManager_ = [NSFileManager defaultManager];
NSURL *url = [NSURL URLWithString:[path stringByAppendingPathComponent:#"video.mp4"]];
if([fileManager_ fileExistsAtPath:[location path]]){
[fileManager_ replaceItemAtURL:url withItemAtURL:location backupItemName:nil options:NSFileManagerItemReplacementUsingNewMetadataOnly resultingItemURL:nil error:nil];
_videoURLPath = url;
}
UISaveVideoAtPathToSavedPhotosAlbum([url path
], nil, nil, nil);
dispatch_async(dispatch_get_main_queue(), ^{
self.progressView_.progress = 0.0;
});
}
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
NSLog(#"%f",(double)totalBytesWritten/(double)totalBytesExpectedToWrite);
dispatch_async(dispatch_get_main_queue(), ^{
self.progressView_.progress = (double)totalBytesWritten/(double)totalBytesExpectedToWrite;
});
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
[KSToastView ks_showToast:#"Download complete"];
NSData *data = [NSData dataWithContentsOfURL:[NSURL fileURLWithPath:_videoURLPath.path]];
[AppHelper saveToUserDefaults:_videoURLPath.path withKey:#"videoURL"];
dispatch_async(dispatch_get_main_queue(), ^{
SAEditUploadViewController *editVC = [self.storyboard instantiateViewControllerWithIdentifier:#"SAEditUploadViewController"];
editVC.videoPathData = data;
[self.navigationController pushViewController:editVC animated:YES];
});
}
I am trying to use NSURLSessionDownloadTask to download a large file. However, I only want to download the first 10MB of that file. I know how to cancel the operation once 10MB has been downloaded, but how do I force a call on didFinishDownloadingToURL in order to retrieve the location of the saved file?
-(void) downloadFileWithProgress
{
NSURL * url = [NSURL URLWithString:#"https://s3.amazonaws.com/hayageek/downloads/SimpleBackgroundFetch.zip"];
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];
NSURLSessionDownloadTask * downloadTask =[ defaultSession downloadTaskWithURL:url];
[downloadTask resume];
}
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
NSLog(#"Temporary File :%#\n", location);
NSError *err = nil;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *docsDir = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSURL *docsDirURL = [NSURL fileURLWithPath:[docsDir stringByAppendingPathComponent:#"out1.zip"]];
if ([fileManager moveItemAtURL:location
toURL:docsDirURL
error: &err])
{
NSLog(#"File is saved to =%#",docsDir);
}
else
{
NSLog(#"failed to move: %#",[err userInfo]);
}
}
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
//You can get progress here
NSLog(#"Received: %lld bytes (Downloaded: %lld bytes) Expected: %lld bytes.\n",
bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
}
If the server supports it the optimal solution would be to use HTTP range requests instead of messing with NSURLSessionDownloadTask.
http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.35.2
I am creating a iPhone app which download icons using NSURLSession & NSURLDownloadTask.
In this case i want to download only the visible cell icons, when i scrolled the table all pending downloadTask get canceled (i.e download task for non-visible cells is must cancel). For this i created a method terminateAllDownloads().
// terminateAllDownloadTask
-(void)terminateAllDownloads
{
NSArray *allDownloads = [self.iconDownloadInProgress allValues];
[allDownloads makeObjectsPerformSelector:#selector(cancelDownload)];
[self.iconDownloadInProgress removeAllObjects];
}
// cancelDownload
-(void)cancelDownload
{
[self.downloadTask cancel];
[self.session invalidateAndCancel];
}
and call this function in dealloc & didRecieveMemoryWarning methods of MasterViewController.m
// dealloc
-(void)dealloc
{
[self terminateAllDownloads];
}
// didReceiveMemeoryWarning
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
[self terminateAllDownloads];
}
but this method is not called single time. how should i do this ?
I am using the NSURLSession Delegates, not completion block
//code
-(void)startDownload
{
appDelgate = [[UIApplication sharedApplication] delegate];
self.fileName = self.appData.name;
self.iconURL = self.appData.iconURL;
NSURLSessionConfiguration *sessionConfig = [NSURLSessionConfiguration defaultSessionConfiguration];
sessionConfig.allowsCellularAccess = NO;
_session = [NSURLSession sessionWithConfiguration:sessionConfig delegate:self delegateQueue:nil];
self.downloadTask = [_session downloadTaskWithURL:[NSURL URLWithString:_iconURL]];
[_downloadTask resume];
}
-(void)cancelDownload
{
[self.downloadTask cancel];
[self.session invalidateAndCancel];
}
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
NSString *trimmedString = [_fileName stringByReplacingOccurrencesOfString:#" " withString:#""];
NSString *appIconDirectory = [[documentsDirectoryForAppIcons absoluteString] stringByAppendingPathComponent:#"appIcons"];
NSURL* destinationUrlForAppIcon = [[NSURL URLWithString:appIconDirectory] URLByAppendingPathComponent:[NSString stringWithFormat:#"%#%#",trimmedString, #".png"]];
NSError *error1;
if([appIconFileManager fileExistsAtPath:[destinationUrlForAppIcon absoluteString]])
{
[appIconFileManager removeItemAtPath:[destinationUrlForAppIcon absoluteString] error:NULL];
}
BOOL status = [appIconFileManager copyItemAtURL:location toURL:destinationUrlForAppIcon error:&error1];
if (status && !error1)
{
[appDelgate.downloadedIcons setValue:destinationUrlForAppIcon.path forKey:self.iconURL];
if(self.completionHandler)
{
self.completionHandler(destinationUrlForAppIcon);
}
}
else
{
NSLog(#"File copy failed: %#", [error1 localizedDescription]);
}
}
Probably you refer to self in the block passed to the NSURLSession producing a retain cycle.
I'm trying to set up a NSInputStream, but my input stream is comes out as nil when I step into the code. The url comes from a Dropbox account.
Getting the file through NSData after I have the url through Dropbox Chooser crashes my iPhone 4 (although not when it is running through XCode). The files are just too big, so I wanted to try NSInputStream.
I saw from I cannot initialize a NSInputStream that the url is supposed to be local. Any idea how to stream a file from Dropbox?
Thanks.
- (void)setUpStreamForFile {
// iStream is NSInputStream instance variable already declared
iStream = [NSInputStream inputStreamWithURL:url];
[iStream setDelegate:self];
[iStream scheduleInRunLoop:[NSRunLoop currentRunLoop]
forMode:NSDefaultRunLoopMode];
[iStream open];
}
Hey don't hesitate to use AFNetworking it is a good framework to manipulate your connections and download content. This is an example to download a file from an URL:
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 *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);
}];
[downloadTask resume];
For more information you can check the official information HERE
so thanks to rmaddy's suggestion, I looked up NSURLConnection but decided to use the features of NSURLSession instead.
I used the NSURLSessionDownloadTask like this. Familiarity with the Dropbox chooser should help.
-(IBAction)didPressChooser:(id)sender {
{
[[DBChooser defaultChooser] openChooserForLinkType:DBChooserLinkTypeDirect
fromViewController:self completion:^(NSArray *results)
{
if ([results count]) {
DBChooserResult *_result = results[0];
NSString *extension = [_result.name pathExtension];
if ([extension isEqualToString:#"m4a"]) {
url = _result.link; //url has already been declared elsewhere
DBFileName = _result.name; //DPFileName has also been declared. It's a string
NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
NSURLSession *session = [NSURLSession sessionWithConfiguration: defaultConfigObject delegate:self delegateQueue: [NSOperationQueue mainQueue]];
NSURLSessionDownloadTask *getFile = [session downloadTaskWithURL:url];
[getFile resume];
}
} else {
// User canceled the action
}
}];
}
}
Once you have that, you put in another method that works as the completion handler.
-(void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location {
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); //I put the file in a temporary folder here so it doesn't take up too much room.
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [NSString stringWithFormat:#"%#/%#", documentsDirectory, DBFileName];
NSData *data = [NSData dataWithContentsOfURL:location];
[data writeToFile:filePath atomically:YES];
url = [NSURL fileURLWithPath:filePath]; //Yep, I needed to re-assign url for use elsewhere.
//do other stuff with your local file now that you have its url!
}
A bonus is that you get to keep track of the download progress with this awesome feature:
-(void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten
totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
NSLog(#"%f / %f", (double)totalBytesWritten,
(double)totalBytesExpectedToWrite);
}
Anyway, hope someone finds this useful. Works much faster on my iPhone 4 than NSURLSessionDataTask which works in a similar manner.
I push my download view, then download file in background model, then update it progress in
delegate (uRLSession:downloadTask:didWriteData: totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:).The progressView can be updated, then pop this controller, then push it again.download file again,The UI can not be updated.
DownloadCode:
- (IBAction)download:(UIButton *)sender {
self.image.backgroundColor = [UIColor whiteColor];
NSString * downloadURLString = [NSString stringWithFormat:#"http://ww3.sinaimg.cn/mw600/bce52ee1jw1e2xe4zdqarj.jpg"];
NSURL* downloadURL = [NSURL URLWithString:downloadURLString];
NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL];
NSURLSessionDownloadTask *task = [[self backgroundURLSession] downloadTaskWithRequest:request];
[task resume];
}
- (NSURLSession *)backgroundURLSession
{
static NSURLSession *session = nil;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
NSString *identifier = #"example.demon";
NSURLSessionConfiguration* sessionConfig = [NSURLSessionConfiguration backgroundSessionConfiguration:identifier];
session = [NSURLSession sessionWithConfiguration:sessionConfig
delegate:self
delegateQueue:[NSOperationQueue mainQueue]];
});
return session;
}
ProgessView update
- (void)URLSession:(NSURLSession *)session
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
float progress = totalBytesWritten*1.0/totalBytesExpectedToWrite;
dispatch_async(dispatch_get_main_queue(),^ {
[self.progress setProgress:progress animated:YES];
});
NSLog(#"Progress =%f",progress);
NSLog(#"Received: %lld bytes (Downloaded: %lld bytes) Expected: %lld bytes.\n",
bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
}
Put below method and your code will work
-(void)viewDidDisappear:(BOOL)animated
{
[super viewDidDisappear:animated];
[self.session invalidateAndCancel];
[self.session finishTasksAndInvalidate];
self.session = nil;
}