user214155 user214155 - 4 months ago 16
iOS Question

Download file on device

Use this code for download file on my device. But on 99% loading interface stop(I can’t click on button). After 20 second everything works fine and loading = 100%. Why interface stop on 99% loading? How to fix it?

- (void)viewDidLoad
{
dispatch_async(dispatch_get_main_queue(), ^{

_session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
});

[self.progressView setProgress:0 animated:NO];
}

- (IBAction)btnClicked:(id)sender {
if(_downloadTask == nil){

_url =[NSURL URLWithString:@"https://www.nsw.gov.au/sites/default/files/bg-view-nsw-media.png"];

_downloadTask = [_session downloadTaskWithURL:_url1];

[_downloadTask resume];

}

else

[_downloadTask resume];
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
dispatch_async(dispatch_get_main_queue(), ^{


NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"image1.mp3"];
BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:NO];


NSData *urlData = [NSData dataWithContentsOfURL:_url];
[urlData writeToFile:filePath atomically:YES];
}

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite;
{
dispatch_async(dispatch_get_main_queue(), ^{
[ _progressView setProgress:totalBytesWritten/totalBytesExpectedToWrite animated:YES];

NSString *percentage = [NSString stringWithFormat:@"%d%%", (int)((totalBytesWritten/totalBytesExpectedToWrite)*100)];
[_label setText:[NSString stringWithFormat:@"%@%%", percentage]];

NSLog(@"%lld", totalBytesWritten);

_label = [[UILabel alloc]initWithFrame:CGRectMake(91, 15, 500, 50)];
[_label setText: percentage];
_label.numberOfLines = 1;
_label.backgroundColor = [UIColor blackColor];
_label.textColor = [UIColor whiteColor];
_label.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:_label];


});


UPD

Then I remove this code

NSData *urlData = [NSData dataWithContentsOfURL:_url];
[urlData writeToFile:filePath atomically:YES];


everything works fine

Answer

You shouldn't put everything in main thread. The only things to keep in main thread are UI updates.

Indeed, every action made in main thread will block the interface until the action finishes. What you want is having your download performing in background, and having only your UI updates in main thread.

What you have to do is following this code :

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    //Do background work
    dispatch_async(dispatch_get_main_queue(), ^{
        //Update UI
    });
});

For your case the code should look like :

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
        NSString *documentsDirectory = [paths objectAtIndex:0];
        NSString *filePath = [documentsDirectory stringByAppendingPathComponent:@"image1.mp3"];
        BOOL fileExists = [[NSFileManager defaultManager] fileExistsAtPath:filePath isDirectory:NO];


        NSData *urlData = [NSData dataWithContentsOfURL:_url];
        [urlData writeToFile:filePath atomically:YES];
    });
}
Comments