2013-06-25 25 views
1

我有以下代碼:IOS:UIAlertView中立即顯示之前,循環執行

UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Loading Content For the First Time..." 
                message:@"\n" 
                delegate:self 
             cancelButtonTitle:nil 
             otherButtonTitles:nil]; 

      UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; 
      spinner.center = CGPointMake(139.5, 75.5); // .5 so it doesn't blur 
      [alertView addSubview:spinner]; 
      [spinner startAnimating]; 
      [alertView show]; 

      for (TCMLevelRemote *level in [obj objectForKey:@"levels"]){ 
       [[TCMExhibitFeedStore sharedStore] createLevel:level]; 
      } 
      [[TCMExhibitFeedStore sharedStore] loadAllLevels]; 
      [[TCMExhibitFeedStore sharedStore] setAllLevels:[[TCMExhibitFeedStore sharedStore] storedLevels]]; 
      [alertView dismissWithClickedButtonIndex:0 animated:YES]; 

的for循環需要一段時間才能執行,因爲它爲下載第一次應用程序運行的一些信息。所以我想要顯示這個通知,以便用戶不會坐在無反應的屏幕上等待。問題是在for循環結束之前alertview不顯示。然後它就馬上消失。我需要改變什麼?

回答

11

聲明你alert-view對象在.H類爲.M類使用無處不在。

將您的for循環代碼放入performSelectorInBackground,以便在Backgroud中運行循環,以便Alertview不等待您的ForLoop完成。

[self performSelectorInBackground: @selector(LoadForLoop) withObject: nil]; 

-(void)LoadForLoop 
{ 
for (TCMLevelRemote *level in [obj objectForKey:@"levels"]){ 
       [[TCMExhibitFeedStore sharedStore] createLevel:level]; 
      } 
      [[TCMExhibitFeedStore sharedStore] loadAllLevels]; 
      [[TCMExhibitFeedStore sharedStore] setAllLevels:[[TCMExhibitFeedStore sharedStore] storedLevels]]; 
      [alertView dismissWithClickedButtonIndex:0 animated:YES]; 

} 

其他解決方案

您還可以使用Grand Central Dispatch (GCD)像波紋管,按您的代碼: -

UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"Loading Content For the First Time..." 
                message:@"\n" 
                delegate:self 
             cancelButtonTitle:nil 
             otherButtonTitles:nil]; 

      UIActivityIndicatorView *spinner = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; 
      spinner.center = CGPointMake(139.5, 75.5); // .5 so it doesn't blur 
      [alertView addSubview:spinner]; 
      [spinner startAnimating]; 
      [alertView show]; 



dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 
      for (TCMLevelRemote *level in [obj objectForKey:@"levels"]){ 
       [[TCMExhibitFeedStore sharedStore] createLevel:level]; 
      } 
      [[TCMExhibitFeedStore sharedStore] loadAllLevels]; 
      [[TCMExhibitFeedStore sharedStore] setAllLevels:[[TCMExhibitFeedStore sharedStore] storedLevels]]; 

     dispatch_async(dispatch_get_main_queue(), ^{ 
      [spinner StopAnimating]; 
      [alertView dismissWithClickedButtonIndex:0 animated:YES]; 
     }); 
    }); 
+0

對於CGD這是最好的選擇,你可以忽略/刪除'performSelector' :)) – danypata

+0

是的,你是對的CGD是我們最好的...... :) –

0

不顯示警報的觀點,因爲你的循環,你會被阻塞主線程,這是必須繪製警報視圖的線程。

在您原來有你的代碼的地方,這樣寫:

// Your original code that creates and sets up the alertView 
UIAlertView* alertView = ... 

// Add this snippet 
NSTimeInterval delay = 0.1; // arbitrary small delay 
[self performSelector:@selector(delayedLoop:) withObject:alertView afterDelay:delay]; 

// Show the alert. Because the delayedLoop: method is invoked 
// "a little bit later", the main thread now should be able to 
// display your alert view 
[alertView show]; 

加入此方法類:

- (void) delayedLoop:(UIAlertView*)alertView 
{ 
    // Add your code that runs the loop and dismisses the alert view 
} 

該解決方案是一個有點「hackish的」,而是因爲你的循環仍然在主線程上下文中運行,所以不會有任何線程問題。如果你願意在輔助線程中執行你的循環,那麼你應該看看Nithin Gohel的答案。

1

我覺得你要找的是創建你的'水平',而你的警報視圖向用戶顯示一個活動指標。

現在,您正在使用與您的UI代碼相同的線程運行for循環。您的代碼將按順序逐行運行。在iOS和Mac OS上,線程的run loop必須有足夠的空間以允許渲染和計時事件,在這種情況下用於動畫。通過阻止運行​​循環直到您的for循環結束,您的UIAlertView將沒有時間在循環之後進行動畫處理,然後您的電話立即隱藏它。

你想要做什麼是你處理轉移到後臺,使用類似Grand Central Dispatch

// Perform all of your UI on the main thread: 
// ... set up your alert views, etc 

// Then shift your logic to a background thread: 
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{ 
    // This block is executed on a background thread, so will not block the UI: 
    for (TCMLevelRemote *level in [obj objectForKey:@"levels"]){ 
     [[TCMExhibitFeedStore sharedStore] createLevel:level]; 
    } 
    [[TCMExhibitFeedStore sharedStore] loadAllLevels]; 
    [[TCMExhibitFeedStore sharedStore] setAllLevels:[[TCMExhibitFeedStore sharedStore] storedLevels]]; 

    // Finally, now that your background process is complete, you can update the interface accordingly by dismissing the alert view: 
    dispatch_async(dispatch_get_main_queue(), ^{ 
     [alertView dismissWithClickedButtonIndex:0 animated:YES]; 
    }); 
}); 

當後臺線程處理,一定要注意必須在執行回該UI的事件是非常重要的主線程

我喜歡將我的任務打包到NSOperation子類中,這兩個子類都有助於將UI與模型邏輯分開,並且還爲我處理GCD。我會把它作爲你的練習。

關於您選擇的用戶界面的注意事項:警告視圖並不意味着通知用戶某些過程。它們意味着提醒用戶發現單個事件已發生。我會建議使用諸如MBProgressHUD之類的東西,尤其是因爲它已經構建了支持GCD方法的doSomethingInBackgroundWithProgressCallback:completionCallback: