簡體   English   中英

iphone nsoperation應用程序凍結

[英]iphone nsoperation application freezes

我已經制作了一個名為˚的NSOperation的子類來實現多個電影下載。 appDelegate.m ,我創建了一個NSOperationQueue對象。

- (void)applicationDidFinishLaunching:(UIApplication *)application {
   queue = [[NSOperationQueue alloc] init];
   [queue setMaximumConcurrentOperationCount:5]
} 

MovieDownloadOperation依賴於一個名為Downloader的類,它實際上下載了電影並給出了回調movieCompletelyDownloadedWithUrl: .
然后,我在MovieDownloadOperationMovieDownloadOperation了一個名為downloadStateMovieDownloadOperation 它有不同的值,如"STARTED""DOWNLOADING""COMPLETED""ERROR"

MyDownloadOperation看起來像

-(id)initWithUrl:(NSURL *)url
{

   if (self = [super init])
   {
      _downloader = [[Downloader alloc] initWithUrl:url];
      _downloadState = @"STARTED" ;
   }
}

-(void)main
{
    while(1)
    {
       if ([_downloadState isEqualToString:@"COMPLETED"])
         {
              NSLog(@"movie downloaded successfully");
              break ;
          }
    }

}

-(void)movieCompletelyDownloadedWithUrl:(NSURL *)url
{
    _downloadState = @"COMPLETED" ;
}

這適用於一部電影,但是當我嘗試下載多部電影時,UI會凍結,直到下載第一部電影。 我認為問題是main方法中的while循環,是否有更好的方法來檢查_downloadState是否更改為"COMPLETED"

目前還不清楚為什么UI會凍結多個操作,但不會只有一個下載。 但是,您的代碼示例引發了一些想法:

  1. 並發操作:

    而不是在main有一個while循環,你通常會將你的操作定義為並發(即從isConcurrent返回YES )。 然后movieCompletelyDownloadedWithUrl將發布isFinished事件,這將觸發操作的完成。

    在如何進行並發操作方面,您可以定義executingfinished屬性:

     @property (nonatomic, readwrite, getter = isFinished) BOOL finished; @property (nonatomic, readwrite, getter = isExecuting) BOOL executing; 

    您可能希望為URL和下載器提供strong屬性:

     @property (nonatomic, strong) NSURL *url; @property (nonatomic, strong) Downloader *downloader; 

    然后,您可能在操作子類中包含以下代碼:

     @synthesize finished = _finished; @synthesize executing = _executing; - (id)init { self = [super init]; if (self) { _finished = NO; _executing = NO; } return self; } - (id)initWithUrl:(NSURL *)url { self = [self init]; if (self) { // Note, do not start downloader here, but just save URL so that // when the operation starts, you have access to the URL. _url = url; } return self; } - (void)start { if ([self isCancelled]) { self.finished = YES; return; } self.executing = YES; [self main]; } - (void)main { // start the download here self.downloader = [[Downloader alloc] initWithUrl:self.url]; } - (void)completeOperation { self.executing = NO; self.finished = YES; } // you haven't shown how this is called, but I'm assuming you'll fix the downloader // to call this instance method when it's done - (void)movieCompletelyDownloadedWithUrl:(NSURL *)url { [self completeOperation]; } #pragma mark - NSOperation methods - (BOOL)isConcurrent { return YES; } - (void)setExecuting:(BOOL)executing { [self willChangeValueForKey:@"isExecuting"]; _executing = executing; [self didChangeValueForKey:@"isExecuting"]; } - (void)setFinished:(BOOL)finished { [self willChangeValueForKey:@"isFinished"]; _finished = finished; [self didChangeValueForKey:@"isFinished"]; } 

    因此,使用這些方法,您可能會像上面一樣調用movieCompletelyDownloadedWithUrl調用completeOperation ,這將確保發布isExecutingisFinished通知。 您還希望對取消事件做出響應,確保在取消操作時取消下載。

    有關更多詳細信息,請參閱“ 並發編程指南”中的 “為並發執行配置操作”部分。

  2. main之前不要啟動下載:

    我沒有看到您的main方法啟動下載。 這讓我感到緊張,你的Downloader初始化方法initWithURL可能正在啟動下載,這將是糟糕的。 您不希望在創建操作時啟動下載,而是在操作開始之前不應該執行此操作(例如, startmain )。 所以,在上面的例子中,我只有initWithURL保存URL,然后main是啟動下載的內容。

  3. NSOperation使用NSURLConnectionDataDelegate方法:

    另外,您沒有分享您的操作如何處理網絡請求。 如果您正在使用NSURLConnectionDataDelegate方法,那么當您在main刪除while循環時,如果不在特定的運行循環中安排NSURLConnection ,則可能會遇到問題。 例如,您可能會這樣做:

     NSURLConnection *connection = [[NSURLConnection alloc] initWithRequest:request delegate:self startImmediately:NO]; [connection scheduleInRunLoop:[NSRunLoop mainRunLoop] forMode:NSRunLoopCommonModes]; [connection start]; 

    如果你沒有使用NSURLConnectionDataDelegate方法,或者你已經解決了這個運行循環問題,那么忽略這個建議,但是,在你的操作中修復main方法的底線,你可能會暴露你的舊的NSURLConnection問題main可能已經隱藏了你。

  4. Downloader如何調用moveCompleteDownloadedWithUrl

    順便說一下,你沒有展示Downloader如何調用moveCompleteDownloadedWithUrl 這看起來很可疑,但我只是希望你在發布時簡化你的代碼。 但是,如果您沒有使用協議委托模式或完成塊模式,那么我會非常擔心您的多個Downloader對象如何通知相應的MyDownloadOperation對象下載完成。 就個人而言,我可能傾向於將這兩個不同的類重構為一個,但這是個人品味的問題。

您可以使用NSTimer檢查下載是否已完成。 它不會凍結你的用戶界面

NSTimer *localTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(checkDownloadStatus) userInfo:nil repeats:YES]; 

-(void)checkDownloadStatus
 {
     if ([_downloadState isEqualToString:@"COMPLETED"])
     {
          NSLog(@"movie downloaded successfully");
          [localTimer invalidate];
     }
 }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM