Ios 更改视图控制器后如何更新UIProgressView以显示NSUrlSession下载进度

Ios 更改视图控制器后如何更新UIProgressView以显示NSUrlSession下载进度,ios,objective-c,nsurlsession,Ios,Objective C,Nsurlsession,我有一个ViewController,用户可以在上面点击一个按钮,开始一个相对较大的下载(大约200mb)。我已经准备好了所有正确的NSUrlSession委托,只要用户不离开ViewController,UIProgressView就会完全更新,所有内容都可以正常下载。我的问题是,在下载文件时,我希望用户能够转到其他ViewController,但仍然能够返回并检查下载进度 但是,在导航到其他ViewController并返回后,委托方法不会触发下载任务。我可以通过NSLog得知文件仍在下载,

我有一个ViewController,用户可以在上面点击一个按钮,开始一个相对较大的下载(大约200mb)。我已经准备好了所有正确的NSUrlSession委托,只要用户不离开ViewController,UIProgressView就会完全更新,所有内容都可以正常下载。我的问题是,在下载文件时,我希望用户能够转到其他ViewController,但仍然能够返回并检查下载进度

但是,在导航到其他ViewController并返回后,委托方法不会触发下载任务。我可以通过NSLog得知文件仍在下载,但UIProgressView不再更新,因为没有调用委托方法。当回到页面时,如何获取当前正在运行的下载任务并激发其委托方法,以便正确更新进度视图

当我导航到下载文件页面时,我设置了NSUrlSession

- (void)viewDidLoad
{
    [super viewDidLoad];

    // Create a session with the custom configuration
    self.session = [self backgroundSession];
}

- (NSURLSession *)backgroundSession
{
    static NSURLSession *session = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,
              ^{
                  // Session Configuration
                  NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.NSUrlSession.app"];

                  // Initialize Session
                  session = [NSURLSession sessionWithConfiguration:sessionConfiguration
                                                          delegate:self
                                                     delegateQueue:nil];
              });

    return session;
}
然后我有一个按钮,创建下载任务并开始下载

- (IBAction)downloadMovie:(id)sender
{
    [UIApplication sharedApplication].networkActivityIndicatorVisible = YES;

    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:LARGE_MOVIE]];

    NSURLSessionDownloadTask *task = [self.session downloadTaskWithRequest:request];

    [task resume];
}
下面是更新UIProgressView的委托方法

- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
    double progress = (double) (totalBytesWritten/1024) / (double) (totalBytesExpectedToWrite/1024);
    dispatch_async(dispatch_get_main_queue(),
                   ^{
                       [self.progressView setProgress:progress animated:NO];
                       NSLog(@"%f", progress);
                   });
}
正如我所说,只要用户没有导航到不同的视图控制器,所有内容都可以完美下载,UIProgressView也可以正确更新。但是,如果用户离开并返回,则新实例化的视图控制器与分配给会话的委托的原始视图控制器不同,因此委托方法不会触发,也不会更新UIProgressView,即使文件仍在后台下载,从NSLog更新中可以看出。

尝试如下:

- (NSURLSession *)backgroundSession
{
    static NSURLSession *staticSession = nil;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken,
              ^{
                  // Session Configuration
                  NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.NSUrlSession.app"];

                  // Initialize Session
                  staticSession = [NSURLSession sessionWithConfiguration:sessionConfiguration
                                                          delegate:self
                                                     delegateQueue:nil];
              });

    return staticSession;
}

另外,尝试
暂停
下载任务,并在回来后再次
恢复
。看看这是否有用

哪些代理功能?您可以检查委托是否仍处于活动状态吗?@Never在URLSession:downloadTask:didWriteData:TotalBytesWrite:totalBytesExpectedToWrite:delegate函数中无望,我更新UIProgressview,并有一条NSLog消息显示(TotalBytesWrite/totalBytesExpectedToWrite)。当我转到另一个视图控制器时,NSLog消息仍在触发,显示当前进度,因此我知道文件仍在某个后台进程上下载。但是,当我回到视图控制器时,如果我在该委托方法上有一个断点,程序不会停止,NSLog消息仍会激发。@尽管如此,我猜想如果我能抓住活动下载任务并使其委托成为新实例化的视图控制器,它将再次开始正确更新UIProgressView,但我不知道怎么做。您是否可以在显示文件仍在下载的同一NSLog中打印NSURLSession的委托?此外,您是否可以检查您是否在某处未设置delegate=nil,例如,
viewdiddemouse
等。。您能给我们看一些代码吗?有什么解决方案吗?@LeXeR,asa解决方案您可以将下载过程与view controller分离,并在单独的层中进行处理,在DownloadManager类中,当视图控制器重新出现时,显示从DownloadManager到ViewController的进度视图的当前进度。我的操作与此完全相同。但问题依然存在。问题是,会话下载程序在再次显示viewcontroller时会获得一个新实例。唯一适合我的解决方案是将ViewController转换为Singleton类。@LeXeR,是的,Singleton是必须的。必须避免重新分配实例以获取最近打开的会话。