2013-06-25 2 views
1

을 실행 나는 다음과 같은 코드가 있습니다IOS : UIAlertView for 루프 직전 쇼

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 루프가 끝날 때까지 alertview가 표시되지 않는다는 것입니다. 그런 다음 곧바로 사라집니다. 무엇을 바꾸어야합니까?

답변

11

하는 .m 클래스의 모든 곳에서 사용하기위한 .H 클래스에 alert-view 객체를 선언합니다.

For 루프 코드를 Backgroud에서 루프를 실행하기 위해 performSelectorInBackground에 넣으십시오. 그러면 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 +1,'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에 루프가 끝날 때까지 애니메이션을 적용 할 시간이 없으므로 dismissWithClickedButtonIndex:animated: 호출이 즉시 숨 깁니다.

// 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 이벤트를 주목하는 것이 중요하다 :

당신이하고 싶은 Grand Central Dispatch 같은 것을 사용하여 배경에 처리를 이동하다 메인 스레드.

내 작업을 모델 논리에서 UI를 분리하는 데 도움이되는 NSOperation 하위 클래스로 패키지화하고 GCD도 처리합니다. 나는 그것을 당신을위한 운동으로 남겨 둘 것입니다.

사용자가 선택한 UI에 관한 부수적 인 설명입니다. 경고보기는 사용자에게 일부 프로세스를 알리기위한 것이 아닙니다. 그것들은 에게 단일 이벤트 이 있음을 알리는 것을 의미합니다. 대신 MBProgressHUD과 같은 것을 사용하도록 조언합니다. 특히 doSomethingInBackgroundWithProgressCallback:completionCallback:으로 GCD 메소드를 지원합니다.