我目前有一个进度视图,显示目前已下载文件的当前数量。当用户单击下载按钮时,进度会成功更新,当他们离开视图控制器并返回时,仍在下载,进度仍会成功更新。但是我的问题是当下载完成并且用户离开并返回到视图时,进度视图不再响应任何更新。我已经对多线程做过一些研究,并且看到许多人建议在主线程中进行任何UI更新,如下所示:
[self performSelectorOnMainThread:@selector(progressUpdate) withObject:nil waitUntilDone:NO];
所以我在我的代码中尝试了它并且仍然得到相同的结果(一旦用户离开并在下载完成后返回视图控制器,进度视图不响应任何更新)。然后我添加了一个NSLog来查看是否正在调用该方法并且调试器输出了NSLog。那么发生了什么?以下是视图控制器的代码:
#import "VideoTest.h"
#import "AppDelegate.h"
#import "FileDownloadInfo.h"
@interface VideoTest ()
@property (nonatomic, strong) NSURLSession *session;
@property (nonatomic, strong) NSMutableArray *arrFileDownloadData;
@property (nonatomic, strong) NSURL *docDirectoryURL;
-(void)initializeFileDownloadDataArray;
-(int)getFileDownloadInfoIndexWithTaskIdentifier:(unsigned long)taskIdentifier;
@end
@implementation VideoTest{
NSString *url;
}
@synthesize moviePlayer;
@synthesize download;
@synthesize videoAlreadyPlaying, progressView;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
//Setting video URl
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
url = @"http://therosary.info/AppVideos/TheChaplet/Information%20on%20Divine%20Mercy.mp4";
//selectors set
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(MPMoviePlayerPlaybackStateDidChange:)
name:MPMoviePlayerPlaybackStateDidChangeNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willEnterFullscreen:) name:MPMoviePlayerWillEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(willExitFullscreen:) name:MPMoviePlayerWillExitFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(enteredFullscreen:) name:MPMoviePlayerDidEnterFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(exitedFullscreen:) name:MPMoviePlayerDidExitFullscreenNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playbackFinished:) name:MPMoviePlayerPlaybackDidFinishNotification object:nil];
//Play the movie
videoAlreadyPlaying=@"TRUE";
self.moviePlayer = [[MPMoviePlayerController alloc] initWithContentURL:[NSURL URLWithString:url]];
[self.view addSubview:moviePlayer.view];
self.moviePlayer.view.frame = CGRectMake(0,64,320,220);
[moviePlayer play];
[self initializeFileDownloadDataArray];
NSArray *URLs = [[NSFileManager defaultManager] URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask];
self.docDirectoryURL = [URLs objectAtIndex:0];
NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.jjdoherty98.Marion_s_Net"];
sessionConfiguration.HTTPMaximumConnectionsPerHost = 5;
self.session = [NSURLSession sessionWithConfiguration:sessionConfiguration
delegate:self
delegateQueue:nil];
if([appDelegate.isAlreadyDownloading isEqual:@"FALSE"] || appDelegate.isAlreadyDownloading==nil){
self.progressView.hidden = YES;
progressView.progress=0;
}
if([appDelegate.isAlreadyDownloading isEqual:@"TRUE"]){
[self performSelectorOnMainThread:@selector(progressUpdate) withObject:nil waitUntilDone:NO];
}
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (self.isMovingFromParentViewController || self.isBeingDismissed) {
NSLog(@"Left View");
[moviePlayer stop];
}
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationPortrait | UIInterfaceOrientationPortraitUpsideDown;
}
- (BOOL)shouldAutorotate{
AppDelegate *mainDelegate = (AppDelegate*)[[UIApplication sharedApplication]delegate];
mainDelegate.fullScreenVideoIsPlaying = @"TRUE";
return YES;
}
- (void)MPMoviePlayerPlaybackStateDidChange:(NSNotification *)notification
{
if (moviePlayer.playbackState == MPMoviePlaybackStatePlaying)
{ //playing
videoAlreadyPlaying = @"TRUE";
}
if (moviePlayer.playbackState == MPMoviePlaybackStateStopped)
{ //stopped
}if (moviePlayer.playbackState == MPMoviePlaybackStatePaused)
{ //paused
}if (moviePlayer.playbackState == MPMoviePlaybackStateInterrupted)
{ //interrupted
}if (moviePlayer.playbackState == MPMoviePlaybackStateSeekingForward)
{ //seeking forward
}if (moviePlayer.playbackState == MPMoviePlaybackStateSeekingBackward)
{ //seeking backward
}
}
- (void)willEnterFullscreen:(NSNotification*)notification {
NSLog(@"willEnterFullscreen");
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
appDelegate.fullScreenVideoIsPlaying = @"TRUE";
}
- (void)enteredFullscreen:(NSNotification*)notification {
NSLog(@"enteredFullscreen");
}
- (void)willExitFullscreen:(NSNotification*)notification {
NSLog(@"willExitFullscreen");
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
appDelegate.fullScreenVideoIsPlaying = @"FALSE";
}
- (void)exitedFullscreen:(NSNotification*)notification {
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
NSLog(@"exitedFullscreen");
if(appDelegate.CurrentProgress==0){
progressView.hidden=TRUE;
}else{
[self performSelectorOnMainThread:@selector(progressUpdate) withObject:nil waitUntilDone:NO];
}
}
- (void)playbackFinished:(NSNotification*)notification {
NSNumber* reason = [[notification userInfo] objectForKey:MPMoviePlayerPlaybackDidFinishReasonUserInfoKey];
switch ([reason intValue]) {
case MPMovieFinishReasonPlaybackEnded:
NSLog(@"playbackFinished. Reason: Playback Ended");
videoAlreadyPlaying=@"FALSE";
[moviePlayer stop];
[moviePlayer play];
break;
case MPMovieFinishReasonPlaybackError:
NSLog(@"playbackFinished. Reason: Playback Error");
videoAlreadyPlaying=@"FALSE";
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Video Failed To Load!"
message:@"Unable to connect to server, please try again later!"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
break;
case MPMovieFinishReasonUserExited:
NSLog(@"playbackFinished. Reason: User Exited");
videoAlreadyPlaying=@"FALSE";
break;
default:
break;
}
[self.moviePlayer setFullscreen:NO animated:YES];
}
-(IBAction)buttonPressed:(id)sender{
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
if([appDelegate.isThereInternet isEqual:@"TRUE"]){
if([appDelegate.isAlreadyDownloading isEqual: @"FALSE"]){
//If there is internet and not already downloading
progressView.hidden=FALSE;
progressView.progress=0;
FileDownloadInfo *fdi = [self.arrFileDownloadData objectAtIndex:0];
fdi.downloadTask = [self.session downloadTaskWithURL:[NSURL URLWithString:fdi.downloadSource]];
fdi.taskIdentifier = fdi.downloadTask.taskIdentifier;
// Start the task.
[fdi.downloadTask resume];
}}
if ([appDelegate.isThereInternet isEqual:@"FALSE"]) {
//No internet available
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Unable to connect to server"
message:@"Internet connection appears to be offline, please try again later!"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
if([appDelegate.isAlreadyDownloading isEqual:@"TRUE"]){
//Is already downloaing
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"File Already Downloading"
message:@"Multiple files can not be downloaded at the same time!"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
}
}
-(void)initializeFileDownloadDataArray{
self.arrFileDownloadData = [[NSMutableArray alloc] init];
[self.arrFileDownloadData addObject:[[FileDownloadInfo alloc] initWithFileTitle:nil andDownloadSource:url]];
}
-(int)getFileDownloadInfoIndexWithTaskIdentifier:(unsigned long)taskIdentifier{
int index = 0;
for (int i=0; i<[self.arrFileDownloadData count]; i++) {
FileDownloadInfo *fdi = [self.arrFileDownloadData objectAtIndex:i];
if (fdi.taskIdentifier == taskIdentifier) {
index = i;
break;
}
}
return index;
}
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location{
NSError *error;
NSFileManager *fileManager = [NSFileManager defaultManager];
NSString *destinationFilename = downloadTask.originalRequest.URL.lastPathComponent;
NSURL *destinationURL = [self.docDirectoryURL URLByAppendingPathComponent:destinationFilename];
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
if ([fileManager fileExistsAtPath:[destinationURL path]]) {
[fileManager removeItemAtURL:destinationURL error:nil];
}
BOOL success = [fileManager copyItemAtURL:location
toURL:destinationURL
error:&error];
if (success) {
int index = [self getFileDownloadInfoIndexWithTaskIdentifier:downloadTask.taskIdentifier];
FileDownloadInfo *fdi = [self.arrFileDownloadData objectAtIndex:index];
fdi.isDownloading = NO;
fdi.downloadComplete = YES;
// Set the initial value to the taskIdentifier property of the fdi object,
// so when the start button gets tapped again to start over the file download.
fdi.taskIdentifier = -1;
// In case there is any resume data stored in the fdi object, just make it nil.
fdi.taskResumeData = nil;
}
else{
NSLog(@"Unable to copy temp file. Error: %@", [error localizedDescription]);
}
}
-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
if (error != nil) {
NSLog(@"Download completed with error: %@", [error localizedDescription]);
appDelegate.isAlreadyDownloading=@"FALSE";
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Failed to download!"
message:@"Unable to connect to the server!"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
});
}
else{
appDelegate.isAlreadyDownloading=@"FALSE";
NSLog(@"Download finished successfully.");
dispatch_async(dispatch_get_main_queue(), ^{
FileDownloadInfo *fdi = [self.arrFileDownloadData objectAtIndex:0];
fdi.isDownloading = NO;
fdi.downloadComplete = YES;
fdi.taskIdentifier = -1;
fdi.taskResumeData = nil;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Download Complete!"
message:@"Go to downloads section to view the file now!"
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alert show];
[alert release];
});
}
}
-(void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
if (totalBytesExpectedToWrite == NSURLSessionTransferSizeUnknown) {
NSLog(@"Unknown transfer size");
}
else{
int index = [self getFileDownloadInfoIndexWithTaskIdentifier:downloadTask.taskIdentifier];
FileDownloadInfo *fdi = [self.arrFileDownloadData objectAtIndex:index];
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
appDelegate.isAlreadyDownloading=@"TRUE";
fdi.downloadProgress = (double)totalBytesWritten / (double)totalBytesExpectedToWrite;
appDelegate.CurrentProgress = fdi.downloadProgress;
[self performSelectorOnMainThread:@selector(progressUpdate) withObject:nil waitUntilDone:NO];
}
}
-(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session{
AppDelegate *appDelegate = [UIApplication sharedApplication].delegate;
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
if ([downloadTasks count] == 0) {
if (appDelegate.backgroundTransferCompletionHandler != nil) {
// Make nil the backgroundTransferCompletionHandler.
appDelegate.backgroundTransferCompletionHandler = nil;
progressView.hidden=TRUE;
// Show a local notification when all downloads are over.
UILocalNotification *localNotification = [[UILocalNotification alloc] init];
localNotification.alertBody = @"All files have been downloaded!";
[[UIApplication sharedApplication] presentLocalNotificationNow:localNotification];
}
}
}];
}
-(void)progressUpdate{
AppDelegate *appDelegate = (AppDelegate*)[[UIApplication sharedApplication] delegate];
if ([appDelegate.isAlreadyDownloading isEqual:@"TRUE"]) {
progressView.progress = appDelegate.CurrentProgress;
[NSTimer scheduledTimerWithTimeInterval:0 target:self selector:@selector(progressUpdate) userInfo:nil repeats:NO];
NSLog(@"Is this method being called");
if (appDelegate.CurrentProgress==1) {
progressView.hidden=TRUE;
}
}
}
@end
任何帮助将不胜感激!