如何在iOS中使用进度在后台下载多个mp4文件?

问题描述:

我在这个问题上的最后2天停滞不前。请帮助我。如何在iOS中使用进度在后台下载多个mp4文件?

我的要求是,如果我下载在第二视图控制器和下载后的背景文件我开始流行到第一视图,控制器,如果我再次推到第二视图控制器随后的进展,应继续下去。

这里发生了什么:我推到第二视图控制器

  1. 我开始下载使用NSMutableURLRequestNSURLConnection
  2. 如果我弹到第一视图,控制器,再次去第二视图控制器,然后所有人都显示为0意味着,如果进展流行期间是34%,并再次推时间的0%显示我的用户界面,但下载继续如常。

我的日志也呈现出完美的,但它的用户界面不显示。我尝试了所有的答案。所有人都有同样的问题。

这是我的全部代码:

在应用程序的委托方法:

CTAppDelegate.h

@property (copy) void (^backgroundSessionCompletionHandler)(); 

CTAppDelegate.m

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler 
{ 
    self.backgroundSessionCompletionHandler = completionHandler; 
} 

2ndViewController.h

- (IBAction)downloadBackground:(id)sender; 
- (IBAction)downloadImage:(id)sender; 
@property (strong, nonatomic) IBOutlet UIImageView *downloadedImage; 
@property (strong, nonatomic) IBOutlet UIProgressView *progressView; 
@end 

2ndViewController.m

#import "CTViewController.h" 
#import "CTSessionOperation.h" 
#import "CTAppDelegate.h" 

static NSString *downloadUrl =  @"http://www.nasa.gov/sites/default/files/ladee_9.4.13_nasa_edge_0.jpg"; 

@interface CTViewController() 

@property (nonatomic, strong) NSOperation *downloadOperation; 

@end 

@implementation CTViewController 

- (void)viewDidLoad 
{ 
    [super viewDidLoad]; 
    // Do any additional setup after loading the view, typically from a nib. 

    self.progressView.progress = 0; 
    self.downloadedImage.hidden = NO; 
    self.progressView.hidden = YES; 
} 

- (void)didReceiveMemoryWarning 
{ 
    [super didReceiveMemoryWarning]; 
    // Dispose of any resources that can be recreated. 
} 

- (IBAction)downloadBackground:(id)sender { 
// [self downloadImageInBackground:YES]; 

    [self.navigationController popViewControllerAnimated:YES]; 
} 

- (IBAction)downloadImage:(id)sender { 
    [self downloadImageInBackground:NO]; 
} 

- (void)downloadImageInBackground:(BOOL)background{ 
    if (self.downloadOperation){ 
     return; 
    } 

    CTSessionOperation *operation = [CTSessionOperation new]; 
    operation.downloadUrl = downloadUrl; 
    operation.progressAction = ^(double bytesWritten, double bytesExpected){ 
     double progress = bytesWritten/bytesExpected; 
     dispatch_async(dispatch_get_main_queue(), ^{ 
     self.progressView.progress = (float) progress; 
     }); 
    }; 
    operation.completionAction = ^(NSURL *imageUrl, BOOL success){ 
     dispatch_async(dispatch_get_main_queue(), ^{ 
      if (success){ 
       UIImage *image = [UIImage imageWithContentsOfFile:[imageUrl path]]; 
       self.downloadedImage.image = image; 
       NSLog(@"Done......."); 
       } 
      self.downloadedImage.hidden = NO; 
      self.progressView.progress = 0; 
      self.progressView.hidden = YES; 
      self.downloadOperation = nil; 
     }); 
    }; 
    operation.isBackground = background; 

    [operation enqueueOperation]; 
    self.downloadedImage.hidden = YES; 
    self.progressView.hidden = NO; 
    self.downloadOperation = operation; 
    } 

    @end 

Operation.h

#import <Foundation/Foundation.h> 

    typedef void (^CTProgressBlock)(double totalBytesWritten, double bytesExpected); 
    typedef void (^CTCompletionBlock)(NSURL *imageUrl, BOOL success); 

    @interface CTSessionOperation : NSOperation<NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDownloadDelegate> 

    @property (nonatomic) NSURLSessionDownloadTask *downloadTask; 
    @property (nonatomic) NSURLSession *session; 
    @property (nonatomic, strong) NSString *downloadUrl; 
    @property (strong) CTProgressBlock progressAction; 
    @property (strong) CTCompletionBlock completionAction; 
    @property (nonatomic, assign) BOOL isBackground; 

    - (void)enqueueOperation; 
    @end 

Operation.m

#import "CTSessionOperation.h" 
    #import "CTAppDelegate.h" 

    @implementation CTSessionOperation 

    - (NSOperationQueue *)operationQueue{ 
     static NSOperationQueue *operationQueue = nil; 
     static dispatch_once_t onceToken; 
     dispatch_once(&onceToken, ^{ 
       operationQueue = [NSOperationQueue new]; 
       [operationQueue setMaxConcurrentOperationCount:NSOperationQueueDefaultMaxConcurrentOperationCount]; 
     }); 

     return operationQueue; 
    } 

    - (NSURLSession *)session { 
     static NSURLSession *session = nil; 
     static NSURLSession *backgroundSession = nil; 
     static dispatch_once_t onceToken; 
     dispatch_once(&onceToken, ^{ 
       NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 
       session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil]; 
       NSURLSessionConfiguration *backgroundConfiguration = [NSURLSessionConfiguration 
     backgroundSessionConfiguration:@"com.captech.NSURLSample.BackgroundSession"]; 
       backgroundSession = [NSURLSession sessionWithConfiguration:backgroundConfiguration 
                 delegate:self 
               delegateQueue:nil]; 
      }); 

      return self.isBackground ? backgroundSession : session; 
    } 

    - (void)enqueueOperation{ 
      [[self operationQueue] addOperation:self]; 
    } 

    #pragma mark - NSOperation 

    - (void)start { 
     if (!self.isCancelled){ 
       NSURL *downloadURL = [NSURL URLWithString:self.downloadUrl]; 
       NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL]; 

       self.downloadTask = [self.session downloadTaskWithRequest:request]; 
       [self.downloadTask resume]; 
      } 
    } 

    #pragma mark - NSURLSessionDownloadDelegate 
    - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location { 
     NSFileManager *fileManager = [NSFileManager defaultManager]; 

     NSArray *urls = [fileManager URLsForDirectory:NSDocumentDirectory inDomains:NSUserDomainMask]; 
     NSURL *documentsDirectory = [urls objectAtIndex:0]; 

     NSURL *originalUrl = [[downloadTask originalRequest] URL]; 
NSURL *destinationUrl = [documentsDirectory URLByAppendingPathComponent:[originalUrl lastPathComponent]]; 
     NSError *error; 

     [fileManager removeItemAtURL:destinationUrl error:NULL]; 
      BOOL success = [fileManager copyItemAtURL:location toURL:destinationUrl error:&error]; 
      if (self.completionAction){ 
       self.completionAction(destinationUrl, success); 
      } 
    } 

     - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite { 
       if (downloadTask == self.downloadTask && self.progressAction){ 
       self.progressAction((double)totalBytesWritten, (double)totalBytesExpectedToWrite); 
      } 
    } 

    - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes { 

    } 

    #pragma mark - NSURLSessionTaskDelegate 

    - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error { 
     if (self.progressAction){ 
       self.progressAction((double)task.countOfBytesReceived, (double)task.countOfBytesExpectedToReceive); 
     } 

     self.downloadTask = nil; 
    } 

    #pragma mark - NSURLSessionDelegate 

     - (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { 
      CTAppDelegate *appDelegate = (CTAppDelegate *)[[UIApplication sharedApplication] delegate]; 
      if (appDelegate.backgroundSessionCompletionHandler) { 
       void (^completionHandler)() = appDelegate.backgroundSessionCompletionHandler; 
      appDelegate.backgroundSessionCompletionHandler = nil; 
    completionHandler(); 
      } 
    } 

    @end 

这是我的全部代码。请检查这... :)

+0

在应用程序委托中有一个变量不断更新它与进度值:)每当你回到第二个VC只是从appdelegate变量读取数据显示进度:)添加一个观察者到该appdelagete变量,所以每当你的请求更改值,你将有机会更新UI :)这就是所有:)简单但是一个非常粗糙的方式来处理事情:) –

+0

添加在视图中的观察者将出现,并在视图中删除将消失:)你不会希望得到通知,当你是第一个VC是不是:)最后,它的快速修复虽然,没有错,但只是不是一个很好的方式来做到这一点:)快乐编码:) –

+0

请你可以给我提供一些我必须做的代码。其实我没有超越积分。 :) –

我会处理下载有点不同,你是怎么做的吧:)

这是我会怎么处理呢:)

1.Declare一类的NSOperation和移动代码的文件下载到这个类

2.Declare的协议在你的NSOpertaion类将当前的下载状态通知,以确认谁该协议

3。在第二个VC启动NSOpertaion和选择委托:)并更新进度相应

  1. 在secondVC的viewWillDisappear其拆下委托,并在将其重新添加作为委托的NSOperation secondVC
  2. 这里viewWillAppear中是编码相同:)

    downloadAssets.h

    #import <Foundation/Foundation.h> 
    
    @protocol AssetDownloadStatusProtocol <NSObject> 
    -(void)updateStatusWithValue:(float) progress; 
    @end 
    
    @interface downloadAssets : NSOperation 
    @property (nonatomic,weak) id<AssetDownloadStatusProtocol> delegate; 
    @property (nonatomic,strong) NSString *urlToDownload; 
    -(id)initWithURL:(NSString *)url; 
    @end 
    
    一点点

    downloadAssets.m

    @implementation downloadChatAssets 
    
    -(id)initWithURL:(NSString *)url{ 
        self=[super init]; 
        self.urlToDownload = url; 
        appdelegate=(AppDelegate *)[[UIApplication sharedApplication] delegate]; 
        return self; 
    } 
    
    - (void)main { 
        // a lengthy operation 
        @autoreleasepool { 
         dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
          if (self.isCancelled) { 
           appdelegate.downloadingOperation = nil; 
           return; 
          } 
          else{ 
           NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 
           AFURLSessionManager *manager = ... //start downloading 
    
           NSURLSessionDataTask *dataTask = [manager dataTaskWithRequest:URLRequest uploadProgress:nil downloadProgress:^(NSProgress * _Nonnull downloadProgress) { 
            if (self.isCancelled) { 
             appdelegate.downloadingOperation = nil; 
             return; 
            } 
            self.progressAmount = downloadProgress.fractionCompleted; 
            dispatch_async(dispatch_get_main_queue(), ^{ 
             [self.delegate updateStatusWithValue:self.progressAmount]; 
            }); 
           } completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) { 
            //handle completion here 
           }]; 
    
           [dataTask resume]; 
          } 
         }); 
        } 
    } 
    @end 
    

    AppDelegate.h

    @property (nonatomic, Strong) NSOperation *downloadingOperation; 
    

    SecondVC.h

    @interface SecondVC : UIViewController <AssetDownloadStatusProtocol> 
    

    SecondVC.m

    -(void)viewWillAppear:(BOOL)animated{ 
        [super viewWillAppear:YES]; 
        if(appdelegate.downloadingOperation) { 
          appdelegate.downloadingOperation.delegate = self; 
        } 
    } 
    
    -(void)viewWillDisappear:(BOOL)animated{ 
        [super viewWillDisappear:YES]; 
        if(appdelegate.downloadingOperation) { 
          appdelegate.downloadingOperation.delegate = nil; 
        } 
    } 
    
    -(void)updateStatusWithValue:(float)progress{ 
        dispatch_async(dispatch_get_main_queue(), ^{ 
         //update your progress here 
         [self.progressView updateProgressBarWithProgressValue:progress]; 
        }); 
    } 
    

    完蛋了:)

    ,只要你想:)开始下载操作

    appdelegate.downloadingOperation = yourDownloaderOperation; 
    [yourDownloaderOperation start]; 
    

    你想阻止它说

    [yourDownloaderOperation stop]; 
    

    有人数超过一个下载操作?考虑使用NSOperationQueue或数组持有的appdelegate :)

    编辑

    按在评论你的要求NSOperations,你可以拿着你的appDelegate引用CTOperation。

    @property (nonatomic, Strong) CTOperation *downloadingOperation; 
    

    你不需要申报,你已经宣布完成块和progressActionBlock :)

    所有您需要做的是,请检查您SecondVC viewWillAppear中的协议。

    -(void)viewWillAppear:(BOOL)animated{ 
         [super viewWillAppear:YES]; 
         if(appdelegate.downloadingOperation) { 
           appdelegate.downloadingOperation.progressAction = ^(double bytesWritten, double bytesExpected){ 
        double progress = bytesWritten/bytesExpected; 
        dispatch_async(dispatch_get_main_queue(), ^{ 
        self.progressView.progress = (float) progress; 
        }); 
    }; 
    appdelegate.downloadingOperation.completionAction = ^(NSURL *imageUrl, BOOL success){ 
        dispatch_async(dispatch_get_main_queue(), ^{ 
         if (success){ 
          UIImage *image = [UIImage imageWithContentsOfFile:[imageUrl path]]; 
          self.downloadedImage.image = image; 
          NSLog(@"Done......."); 
          } 
         self.downloadedImage.hidden = NO; 
         self.progressView.progress = 0; 
         self.progressView.hidden = YES; 
         self.downloadOperation = nil; 
        }); 
    }; 
         } 
        } 
    
        -(void)viewWillDisappear:(BOOL)animated{ 
         [super viewWillDisappear:YES]; 
         if(appdelegate.downloadingOperation) { 
           appdelegate.downloadingOperation.progressAction = nil; 
           appdelegate.downloadingOperation.completionAction = nil; 
         } 
        } 
    

    ,并在您downloadImageInBackground方法,而不是self.downloadOperation = operation;说'appdelegate.downloadingOperation =操作;

    免责声明

    请注意,这个答案提供的代码只是为了说明概念的目的。我可能有句法错误或表达错误。请不要盲目复制粘贴。

    简单的权利???有疑惑,平我:)快乐编码:)

开始=“4”>
+0

我做了Operation类。但我只需要保存进度状态。是的,它有不止一个下载操作。等待我用代码更新我的问题。 –

+0

@ s-r-nayak:我在代码中丢失了一点。你已经在你的viewController中声明了NSOperation,当你从SecondVC弹出时,它的属性包括NSOperations将被删除。所以,尽管你的操作仍然存在,你却失去了对它的引用当你回到SecondVC时,你的操作属性总是为零。你打算如何获得执行操作的参考?你没有在appdelegate中提及它,也没有NSOperationQueue。当你回到第二次哥们时,你怎么能期望手术告诉你进展? –

+0

好的,然后我必须做的。请在代码中引导我? –