设备上的下载文件是阻塞界面

时间:2016-07-23 16:07:49

标签: ios objective-c user-interface

在我的设备上使用此代码下载文件。但是在99%的加载界面停止(我无法点击按钮)。 20秒后一切正常,装载= 100%。为什么界面停止在99%加载?如何解决?

- (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

然后我删除此代码

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

一切正常

2 个答案:

答案 0 :(得分:0)

不应将{em>所有内容放在main thread中。 main thread中唯一要保留的内容是UI updates

实际上,main thread中的每个操作都会阻止界面,直到操作完成。您想要的是在background中执行下载,并在UI updates中仅 main thread

您需要遵循以下代码:

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

对于您的情况,代码应如下所示:

- (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];
    });
}

答案 1 :(得分:0)

中的代码
import React from 'react';  
import ReactDOM from 'react-dom';
import Router from 'react-router';  
import { DefaultRoute, Link, Route, RouteHandler } from 'react-router';

import LoginHandler from './components/Login.js';

let App = React.createClass({  
  render() {
    return (
      <div className="nav">
        <Link to="app">Home</Link>
        <Link to="login">Login</Link>

        {/* this is the importTant part */}
        <RouteHandler/>
      </div>
    );
  }
});

let routes = (  
  <Route name="app" path="/" handler={App}>
    <Route name="login" path="/login" handler={LoginHandler}/>
  </Route>
);

Router.run(routes, function (Handler) {  
  ReactDOM.render(<Handler/>, document.body);
});

将在主线程上执行。在大多数情况下,您应该避免在那里执行长进程,因为在您的任务完成之前,ui(您的按钮)无法响应。

所以尝试使用类似的东西进行后台下载

dispatch_async(dispatch_get_main_queue(), ^{ /* code */ });

并在下载完成后使用您的解决方案在主线程上更新您的ui。