2014-05-15 35 views
0

我正在從互聯網下載zip文件並將其解壓縮。這個過程需要15秒左右。我想顯示給用戶的某種時間。作爲開始,我只想在下載完成並開始解壓縮時更新我的​​_countUpViewUIView上的UILabel。我相信,我需要對持有UILabel,但我似乎無法找出什麼我做錯了的視圖中使用setNeedsDisplay,這裏是我的代碼:如何使用setNeedsDisplay方法與代碼同步更新UILabel

NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"http://URLtothiszipfile>/all.zip"]]; 
NSData *slicedata= [NSData dataWithContentsOfURL:url]; 
NSError *error; 
NSString *isignsPath = [NSString stringWithFormat:@"%@/iSigns",docsDir]; 
if (![filemgr fileExistsAtPath:isignsPath]){ //Does directory already exist? 
    if (![filemgr createDirectoryAtPath:isignsPath withIntermediateDirectories:NO attributes:nil error:&error]){ 
     NSLog(@"Create directory error: %@", error); 
    } 
} 
thePathAndName= [NSString stringWithFormat:@"%@/iSigns/all.zip", docsDir]; 
[slicedata writeToFile:thePathAndName atomically:YES]; 
_countUpLab.text= @"Unzipping"; 
[self displayCountUpNOW]; 
NSLog(@"Unzipping"); 
[SSZipArchive unzipFileAtPath:thePathAndName toDestination:isignsPath overwrite:true password:@"" error:&error]; 
if (error.code!= noErr){ 
    NSLog(@"Unzip error"); 
    return; 
}else{ 
    NSLog(@"Unzipped successfully"); 
} 

而且setNeedsDisplay方法是:

- (void) displayCountUpNOW { 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [_countUpView setNeedsDisplay]; 
    }); 
} 

我將標籤設置爲「解壓縮」大約10秒後,我的標籤不會更改爲「解壓縮」,直到NSLog顯示「解壓成功」。

在這10秒鐘內,解壓縮發生,但是我想用來更新標籤的計時器每秒都會停止執行,所以我無法在標籤中顯示流逝的時間。

請幫我理解這個異步環境。
卡門

EDIT-EDIT-EDIT 下面的代碼似乎異步工作,我甚至有我的經時指示器工作,因爲我的定時器未停止。我無法在SSZipArchive中找到沒有文件的方法,因此我將保存文件保存在其中。我如何做鄧肯?再次感謝,這非常漂亮!

還有一個問題:什麼是最好的方式來知道什麼時候異步請求仍然未完成,通過設置一個全局標誌變量,當請求時,並在異步過程完成時清除它?

gotALL= 0; 
    _countUpLab.text= @"Downloading"; 
    NSURL* url = [NSURL URLWithString:[NSString stringWithFormat:@"http://URLtothiszipfile>/all.zip"]]; 
    NSURLRequest *urlRequest = [NSURLRequest requestWithURL:url]; 
    [NSURLConnection sendAsynchronousRequest:urlRequest queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *slicedata, NSError *error1){ 
     if ([slicedata length]> 0 && error1== nil){ 
     NSString *isignsPath = [NSString stringWithFormat:@"%@/iSigns",docsDir]; 
     if (![filemgr fileExistsAtPath:isignsPath]){ //Does directory already exist? 
      NSError *error2; 
      if (![filemgr createDirectoryAtPath:isignsPath withIntermediateDirectories:NO attributes:nil error: &error2]){ 
       NSLog(@"Create directory error: %@", error2); 
       [self endCountUp]; 
       return; 
      } 
     } 
     thePathAndName= [NSString stringWithFormat:@"%@/iSigns/all.zip", docsDir]; 
     [slicedata writeToFile:thePathAndName atomically:YES]; 
     _countUpLab.text= @"Unzipping"; 
     NSLog(@"Unzipping"); 
     dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
      NSError *error3; 
      [SSZipArchive unzipFileAtPath:thePathAndName toDestination:isignsPath overwrite:true password:@"" error:&error3]; 
      dispatch_async(dispatch_get_main_queue(), ^(void) { 
       if (error3.code!= noErr){ 
        NSLog(@"Unzip error %@", error3.description); 
        [self endCountUp]; 
        return; 
       }else{ 
        NSLog(@"Unzipped successfully"); 
        gotALL= 1; 
        [self endCountUp]; 
        return; 
       } 
      }); 
     }); 
     }else if ([slicedata length]== 0 && error1== nil){ 
     //todo yet 
     }else if (error1!= nil){ 
     //todo yet 
     } 
    }]; 
+1

試着移動'_countUpLab.text = @「解壓縮」;'dispatch_async塊內部 – sha

+0

好想法,但似乎沒有工作。謝謝卡門 – Carm100

回答

4

很多與您的代碼有關的問題。首先,您的當前代碼將鎖定用戶界面,直到下載完成。這很糟糕,即使對於短下載。如果出現網絡問題,即使是短文件,也可以將用戶界面鎖定長達2分鐘。

您應該使用異步下載而不是同步下載文件。

其次,當您的代碼返回並且應用程序訪問事件循環時,UI更新只會呈現在屏幕上。使用這種方法的代碼:

  • 設置標籤文本「做的東西」
  • 做一些耗時
  • 更改標籤文本「與東西做」

不工作。 「做的東西」的文字一直沒有出現在標籤,因爲標籤更改後才繪製你的代碼完成並返回,到那時,你已經替換爲標籤文本「與東西做。」

這裏是你應該做的,而不是:

使用NSURLConnection的方法sendAsynchronousRequest:queue:completionHandler:。在completionHandler塊中下載完成後,將要運行的代碼放入。

該方法爲您處理背景材料,然後在下載完成後在主線程上運行完成塊。這是一個精巧的系統方法。

應該可以使用dispatch_async從後臺解壓縮。 (我不熟悉SSZipArchive庫,所以我還不能肯定它是線程安全的,但它應該

的基本思路是:

  • 顯示「下載「 信息。
  • 創建一個NSURLRequest。
  • 使用sendAsynchronousRequest:queue:completionHandler:異步提交請求。
  • 在完成處理:
    • 更改消息「解壓」
    • 保存下載數據到磁盤,如果解壓縮庫需要將其保存到一個文件中。如果zip庫可以從內存中解壓縮,則可以跳過此步驟。
    • 使用dispatch_async解壓縮從默認的優先級全局隊列
    • 文件在解壓縮塊的末尾,使用dispatch_async(dispatch_get_main_queue())來更改標籤,以「解壓縮完成」或任何你想說的話。 (你必須將消息發送到主隊列,因爲你不能在UI從後臺線程改變。)

嘗試找出如何編寫上述方法。如果您遇到困難,請發佈您嘗試編輯的帖子,我們可以爲您提供指導,但如果您嘗試自行編寫此代碼,則會更好。你將學習這種方式而不是複製/粘貼。

+0

感謝您花時間提供我基本可以理解的優秀建議。我同意你的方式來幫助我,我的觀點是,這將永遠統治!我喜歡這樣!卡門 – Carm100