2014-10-17 12 views
6

Różnica między starszym UIAlertView a nowym UIAlertController polega na tym, że ten drugi musi być przedstawiony na określonym kontrolerze widoku z presentViewController:animated:completion:. Stwarza to problem niezręczny dla mojego przypadku użycia: co, jeśli już jest wyświetlany UIAlertController (na przykład okno dialogowe oceny), gdy zostanie wyświetlony drugi kontroler widoku (np. Okno dialogowe błędu z powodu nieudanego połączenia sieciowego). Doświadczyłem, że w tym przypadku drugi UIAlertController po prostu się nie wyświetla.Pokaż UIAlertController, jeśli już pokazuje Alert

Edycja: W tej chwili próbuję pokazać alert, nie wiem, czy obecnie jest coś prezentacji.

Jak sobie radzisz z tą sytuacją?

+0

[Wątek] [1] wyjaśnić poprawnie, jak rozwiązywać podobne problemy [1]: http://stackoverflow.com/questions/21179922/can-i-check-if- any-uialertview-displaying-right-now –

+0

Rozwiązania w drugim wątku są delikatne i brzydkie i prawdopodobnie ulegną uszkodzeniu w iOS8. – fabb

Odpowiedz

4

znalazłem obejście, aby dowiedzieć się, które viewcontroller mogę prezentujemy alarmować. Ja również wysłana odpowiedź here:

@implementation UIViewController (visibleViewController) 

- (UIViewController *)my_visibleViewController { 

    if ([self isKindOfClass:[UINavigationController class]]) { 
     // do not use method visibleViewController as the presentedViewController could beingDismissed 
     return [[(UINavigationController *)self topViewController] my_visibleViewController]; 
    } 

    if ([self isKindOfClass:[UITabBarController class]]) { 
     return [[(UITabBarController *)self selectedViewController] my_visibleViewController]; 
    } 

    if (self.presentedViewController == nil || self.presentedViewController.isBeingDismissed) { 
     return self; 
    } 

    return [self.presentedViewController my_visibleViewController]; 
} 

@end 

// To show a UIAlertController, present on the following viewcontroller: 
UIViewController *visibleViewController = [[UIApplication sharedApplication].delegate.window.rootViewController my_visibleViewController]; 
3

Od UIAlertControllor sama jest UIViewController, można przedstawić drugą UIAlertController na szczycie pierwszej przedstawiając od istniejącego:

alertController.PresentViewController(alertController2, animated: true, completionHandler: null); 
+0

Problem polega na tym, że najpierw trzeba znaleźć top prezentowany kontroler widoku. Załóżmy, że nie wiem, czy wyświetlane są alarmy amy lub inne pokazywane kontrolery view. – fabb

+0

Użyj tego, aby uzyskać najwyższą ViewController: \t prywatną UIViewController GetTopPresentedViewController() \t { \t \t UIViewController currentVC = to.viewController; \t \t while (prawda) \t \t { \t \t \t UIViewController nextVC = currentVC.PresentedViewController; \t \t \t if (nextVC == null) \t \t \t { \t \t \t \t powrotu currentVC; \t \t \t} \t \t \t \t currentVC = nextVC; \t \t \t} \t \t} – Bbx

+0

zobaczyć moją odpowiedź - nie zapomnij 'isBeingDismissed' flagę. – fabb

0

Ten kod spełnienia wymogu, gdy aplikacja ma przedstawić pewne ostrzeżenie w oknie i przed obecny jego sprawdzanie, czy jest jakiś inny AlertController prezentowane już, jeśli przedstawiane następnie przedstawić alertu Pojawił się Alertcontroller inaczej prezentują go w oknie.

Oto jeszcze jedna alternatywa, którą można zoptymalizować zgodnie z wymaganiami.

 func showAlert(message:String) { 

     if let alert = self.checkIfAlertViewHasPresented() { 
      alert.presentViewController(alertController, animated: true, completion: nil) 

     } else { 
      self.window?.rootViewController!.presentViewController(alertController, animated: true, completion: nil) 
     } 
    } 

    func checkIfAlertViewHasPresented() -> UIAlertController? { 

     if var topController = UIApplication.sharedApplication().keyWindow?.rootViewController { 
      while let presentedViewController = topController.presentedViewController { 
       topController = presentedViewController 
      } 
      if topController is UIAlertController { 
       return (topController as! UIAlertController) 
      } else { 
       return nil 
      } 
     } 
     return nil 
    } 
+0

Nie obejmuje to kilku specjalnych przypadków, które są uwzględnione w zaakceptowanej odpowiedzi. – fabb

+0

@fabb Uzgodnione z tobą. Już napisałem to przed napisaniem kodu o warunek spełniony przez fragment kodu. Uważam moją odpowiedź za opcję dodatkową, jeśli jakiś początkujący deweloper miałby problem z zrozumieniem innych złożonych warunków. – iDevAmit

+0

IMHO, szczególnie początkujący powinni nauczyć się robić rzeczy prawidłowo, bez urazy – fabb

0

To jest to, czego używam. w ten sposób, jeśli alert jest już wyświetlany, wolę, aby użytkownik go zwolnił, a nie aplikację. Tak więc, gdy widok jest już wyświetlany, czekam tylko 5 sekund i spróbuję ponownie.

Chcę tylko dodać, nie testowałem tego zbyt wiele, ale działa. (Z 1 testu zrobiłem), więc mam nadzieję, że czegoś nie brakuje, bo myślałem o tym problemie przez długi czas, i to brzmi zbyt proste rozwiązanie :)

-(void) alertUserWithTitle:(NSString*) title Message:(NSString*) message 
{ 
    UIAlertController* alert = [UIAlertController alertControllerWithTitle:title                    message:message 
                      preferredStyle:UIAlertControllerStyleAlert]; 

        UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault 
                      handler:^(UIAlertAction * action) {}]; 

        [alert addAction:defaultAction]; 

        if(self.presentedViewController == nil) 
        { 
         [self presentViewController:alert animated:YES completion:nil]; 
        }else 
        { 
         double delayInSeconds = 2.0; 
         dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC); 

         dispatch_after(popTime, dispatch_get_main_queue(), ^(void){ 

          [self alertUserWithTitle:title Message:message]; 

         }); 

        } 
} 
+0

Dobry do niektórych przypadków użycia. Nie jest to rozwiązanie idealne, jeśli alert powinien blokować dalszą interakcję z użytkownikiem. – fabb

0

Oto rozwiązanie używam w Swift 3. jest to funkcja, która pokazuje alert dla użytkownika, a jeśli nazwać to wiele razy, zanim użytkownik odrzucił alert , doda nowy tekst alertu do alertu, który już jest prezentowany. Jeśli wyświetlany jest inny widok, alert nie zostanie wyświetlony. Nie wszyscy zgodzą się z tym zachowaniem, ale działa to dobrze w prostych sytuacjach.

extension UIViewController { 
    func showAlert(_ msg: String, title: String = "") { 
     if let currentAlert = self.presentedViewController as? UIAlertController { 
      currentAlert.message = (currentAlert.message ?? "") + "\n\nUpdate:\(title): \(msg)" 
      return 
     } 

     // create the alert 
     let alert = UIAlertController(title: title, message: msg, preferredStyle: UIAlertControllerStyle.alert) 
     alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.default, handler: nil)) 

     // show the alert 
     self.present(alert, animated: true, completion: nil) 
    } 
} 
Powiązane problemy