UIAlertController가 이미 표시되고 있는지 확인하는 가장 좋은 방법은 무엇입니까?


109

로드 될 때 각 셀이 UIAlertController에 표시하도록 선택한 NSError를 반환 할 수있는 tableview가 있습니다. 문제는 여러 오류가 반환되면 콘솔 에이 오류가 발생한다는 것입니다.

경고 : MessagesMasterVC에서 UIAlertController : 0x14e64cb00을 표시하려고합니다 : 이미 표시되고있는 0x14e53d800 (null)

이상적으로는 UIAlertController 확장 메서드에서 이것을 처리하고 싶습니다.

class func simpleAlertWithMessage(message: String!) -> UIAlertController {

    let alertController = UIAlertController(title: nil, message: message, preferredStyle: UIAlertControllerStyle.Alert)
    let cancel = UIAlertAction(title: "Ok", style: .Cancel, handler: nil)

    alertController.addAction(cancel)
    return alertController
}

matt의 답변에 따라 확장을 UIViewController 확장으로 변경하여 훨씬 깔끔하고 많은 presentViewController 코드를 절약했습니다.

    func showSimpleAlertWithMessage(message: String!) {

    let alertController = UIAlertController(title: nil, message: message, preferredStyle: UIAlertControllerStyle.Alert)
    let cancel = UIAlertAction(title: "Ok", style: .Cancel, handler: nil)

    alertController.addAction(cancel)

    if self.presentedViewController == nil {
        self.presentViewController(alertController, animated: true, completion: nil)
    }
}

업데이트 된 코드를 게시 해 주셔서 감사합니다.
djbp apr

또한 나머지 코드 (UIAlertController를 설정하는 세 줄)를 If 문으로 옮겼습니다. 왜냐하면 여전히 다음 오류 (할당을 해제하는 동안 뷰 컨트롤러의 뷰를로드하려고 시도하는 것은 허용되지 않고 정의되지 않은 동작)
Kitson

아래 링크에서 솔루션을 참조하고 싶습니다. stackoverflow.com/a/39994115/1872233
iDevAmit 2010 년

답변:


119

"이미 제공하는"UIAlertController가 아니라 MessagesMasterVC입니다. 뷰 컨트롤러는 한 번에 하나의 다른 뷰 컨트롤러 만 표시 할 수 있습니다. 따라서 오류 메시지입니다.

즉, 뷰 컨트롤러에에게 지시 한 presentViewController:...경우 제시된 뷰 컨트롤러가 해제 될 때까지 다시 할 수 없습니다.

당신은 MessagesMasterVC가 이미 뷰 컨트롤러를 제공하고 있는지 물어볼 수 있습니다 presentedViewController. 그렇지 않다면 nil말하지 마십시오 presentViewController:.... 이미 뷰 컨트롤러를 제공하고 있습니다.


2
컨트롤러 A가 컨트롤러 B를 제시하고 B가 UIAlertController를 제시하려는 경우 작동합니까? 저도 같은 오류가 있어요 나는 그림 B는 이미 내가 알고하지 않는 무언가를 제시 할 수없는 경우, 또는 B가 제시되고 있기 때문에 문제가있는 경우
크리스토퍼 시스코

1
@ChristopherFrancisco 새로운 질문으로 물어보세요!
matt

@ChristopherFrancisco 안녕하세요, 나는 지금 같은 문제가 있습니다. 새로운 질문을 했습니까? 또는 어디서 해결할 수 있습니까? 그렇다면 어떻게?
Abed Naseri

훌륭한 대답, 그것은 미묘한 차이입니다.
ScottyBlades

29
if ([self.navigationController.visibleViewController isKindOfClass:[UIAlertController class]]) {

      // UIAlertController is presenting.Here

}

22
당신이하는 일을 설명하기 위해 당신의 대답에 텍스트를 넣는 것은 항상 좋은 생각입니다. 좋은 답을 쓰는 방법을 읽으십시오 .
Jørgen R

1
설명이 부족해서 좋은 대답은 아니었지만, 그 방법은 저에게 많은 도움이되었습니다. 문제는 UIAlertController짧은 연속으로 발사 를 제시하기 위해 내 코드를 호출하는 이벤트가 두 개 이상 있다는 것 입니다. 비슷한 문제가 있으면 이것을 확인하십시오.
ChidG

10

위의 제안 된 솔루션에는 내 관점에서 볼 때 필수적인 문제가 있습니다.

ViewController에게 'presentedViewController'속성이 nil이고 대답이 거짓인지 물어 보면 UIAlertController가 이미 제시되어 있다는 결론에 도달 할 수 없습니다. 예를 들어 popOver와 같은 표시되는 ViewController 일 수 있습니다. 따라서 Alert가 이미 화면에 있는지 여부를 확실히 확인하는 제안은 다음과 같습니다 (presentedViewController를 UIAlertController로 캐스팅).

if self.presentedViewController == nil {
   // do your presentation of the UIAlertController
   // ...
} else {
   // either the Alert is already presented, or any other view controller
   // is active (e.g. a PopOver)
   // ...

   let thePresentedVC : UIViewController? = self.presentedViewController as UIViewController?

   if thePresentedVC != nil {
      if let thePresentedVCAsAlertController : UIAlertController = thePresentedVC as? UIAlertController {
         // nothing to do , AlertController already active
         // ...
         print("Alert not necessary, already on the screen !")

      } else {
         // there is another ViewController presented
         // but it is not an UIAlertController, so do 
         // your UIAlertController-Presentation with 
         // this (presented) ViewController
         // ...
         thePresentedVC!.presentViewController(...)

         print("Alert comes up via another presented VC, e.g. a PopOver")
      }
  }

}


5

다음은 Swift 3에서 사용하는 솔루션입니다. 사용자에게 경고를 표시하는 기능입니다. 사용자가 경고를 해제하기 전에 여러 번 호출하면 이미 표시되고있는 경고에 새 경고 텍스트를 추가합니다. . 다른보기가 표시되는 경우 경고가 표시되지 않습니다. 모든 사람이 그 행동에 동의하는 것은 아니지만 간단한 상황에서는 잘 작동합니다.

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)
    }
}

좋아요, 이것이 제가 필요한 것입니다. iOS 13에서도 작동합니다.
Zoltan Vinkler 19.11.

3

뷰 컨트롤러가 있는지 간단히 확인할 수 있습니다.

표시되면 UIAlertController의 종류인지 확인하십시오.

    id alert = self.presentedViewController;

    if (alert && [alert isKindOfClass:[UIAlertController class]]) 
      {
           *// YES UIAlertController is already presented*
      }
    else
       {
        // UIAlertController is not presented OR visible.
       }

1

경고가 이미 표시된 경우 한 줄로 테스트 할 수 있습니다.

if self.presentedViewController as? UIAlertController != nil {
    print ("alert already presented")
}

답변에 코드를 설명 할 수 있습니다. 이 관련 정보를 추가하는 방법 또는 이미 허용 또는 높은 평가 대답 읽기가있을 때 좋은 답변 작성하는 방법
레아 그리


0

나는 그것을 감지하고 제거하고 경고하는 데 사용했습니다.

먼저 다음과 같은 기능으로 경고를 생성합니다.

 var yourAlert :UIAlertController!

 func useYouAlert (header: String, info:String){


    yourAlert = UIAlertController(title:header as String, message: info as String, preferredStyle: UIAlertControllerStyle.alert)



    let okAction = UIAlertAction(title: self.langText[62]as String, style: UIAlertActionStyle.default) { (result : UIAlertAction) -> Void in
        print("OK") 

    }


    yourAlert.addAction(okAction)
    self.present(yourAlert.addAction, animated: true, completion: nil)

}

그리고 코드의 다른 부분에서

    if yourAlert != nil {

      yourAlert.dismiss(animated: true, completion: nil)

    }

0

최신 Swift 언어의 경우 다음을 사용할 수 있습니다.

var alert = presentedViewController

if alert != nil && (alert is UIAlertController) {
    // YES UIAlertController is already presented*
} else {
    // UIAlertController is not presented OR visible.
}

0

현재 컨트롤러를 닫고 경고 컨트롤러를 다음과 같이 표시합니다.

 func alert(_ message:String) {
  let alert = UIAlertController(title: "Error!", message: message, preferredStyle: .alert)
  alert.addAction(UIAlertAction(title: "Dismiss", style: .default, handler: nil))
  self.dismiss(animated: false, completion: nil)
  self.present(alert, animated: true,completion: nil)
    }

0

Swift 4.2+ 답변

if UIApplication.topViewController()!.isKind(of: UIAlertController.self) { 
            print("UIAlertController is presented")}

최고의 Viewcontroller를 얻는 방법을 모르는 사람들을 위해

extension UIApplication {


public class func topViewController(_ base: UIViewController? = UIApplication.shared.keyWindow?.rootViewController) -> UIViewController? {
    if let nav = base as? UINavigationController {
        return topViewController(nav.visibleViewController)
    }
    if let tab = base as? UITabBarController {
        if let selected = tab.selectedViewController {
            return topViewController(selected)
        }
    }
    if let presented = base?.presentedViewController {
        return topViewController(presented)
    }
    return base
}}

스위프트 5+ 대답 'keyWindow은' 아이폰 OS 13.0에서 사용되지 않습니다 제안 편집

if UIApplication.topViewController()!.isKind(of: UIAlertController.self) { 
            print("UIAlertController is presented")}

최고의 Viewcontroller를 얻는 방법을 모르는 사람들을 위해

extension UIApplication {


public class func topViewController(_ base: UIViewController? = UIApplication.shared.windows.first?.rootViewController) -> UIViewController? {
    if let nav = base as? UINavigationController {
        return topViewController(nav.visibleViewController)
    }
    if let tab = base as? UITabBarController {
        if let selected = tab.selectedViewController {
            return topViewController(selected)
        }
    }
    if let presented = base?.presentedViewController {
        return topViewController(presented)
    }
    return base
}}

0

UIAlertController 요청을 쌓기 위해 큐를 만들어야한다는 것을 알았습니다.

NSMutableArray *errorMessagesToShow; // in @interface
errorMessagesToShow=[[NSMutableArray alloc] init];  // in init

-(void)showError:(NSString *)theErrorMessage{
    if(theErrorMessage.length>0){
        [errorMessagesToShow addObject:theErrorMessage];
        [self showError1];
    }
}
-(void)showError1{
    NSString *theErrorMessage;
    if([errorMessagesToShow count]==0)return; // queue finished

    UIViewController* parentController =[[UIApplication sharedApplication]keyWindow].rootViewController;
    while( parentController.presentedViewController &&
      parentController != parentController.presentedViewController ){
        parentController = parentController.presentedViewController;
    }
    if([parentController isKindOfClass:[UIAlertController class]])return;  // busy

    // construct the alert using [errorMessagesToShow objectAtIndex:0]
    //  add to each UIAlertAction completionHandler [self showError1];
    //   then

    [errorMessagesToShow removeObjectAtIndex:0];
    [parentController presentViewController:alert animated:YES completion:nil]; 
}

-3

현재 컨트롤러를 닫고 원하는 컨트롤러를 제시하기 만하면됩니다.

self.dismiss(animated: false, completion: nil)

self.displayAlertController()

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.