【问题标题】:Check if a UIAlertView is showing检查是否显示 UIAlertView
【发布时间】:2011-02-01 12:05:46
【问题描述】:

我有一个方法可以发布 HTTP 数据并在出现错误时显示 UIAlertView。如果我有多个 HTTP 帖子,我将为每个错误显示多个 UIAlertView。

我只想在不显示其他 UIAlertView 的情况下显示 UIAlertView。 我如何确定这一点?

【问题讨论】:

    标签: ios iphone objective-c uialertview


    【解决方案1】:

    为什么不只检查由 UIAlertView 类维护的可见属性?

    if (_alert) //alert is a retained property
    {
        self.alert = [[[UIAlertView alloc] initWithTitle:@"Your Title"
                                                 message:@"Your message" 
                                                delegate:self
                                       cancelButtonTitle:@"Cancel"
                                       otherButtonTitles:@"OK"] autorelease];
    }
    if (!_alert.visible)
    {
        [_alert show];
    }
    

    【讨论】:

    • 从 iOS9 开始,被替换的 'UIAlertController' 没有属性 'visible'。
    【解决方案2】:

    在调用 UIAlertView 上的 show 方法之前调用 set an ivar 的对象。

    ...
    
    if (!self.alertShowing) {
        theAlert = [[UIAlertView alloc] initWithTitle:title message:details delegate:self cancelButtonTitle:nil otherButtonTitles:@"Okay", nil];
        self.alertShowing = YES;
        [theAlert show];
    }
    
    ...
    

    然后在警报管理的委托方法中将标志 ivar 设置为 no:

    - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
    {
      ...
          self.alertShowing = NO;
    }
    

    如果您希望警报按顺序显示,我会发布通知以将每条消息添加到队列中,然后仅在解除警报后从队列中取出一条消息。

    【讨论】:

    • 如果警报正在显示但它可能属于其他视图控制器而您不知道每个控制器怎么办?
    • 这听起来与原始发帖人提出的问题不同。提供答案的第一部分,暗示拥有视图控制器是已知的,因此您的后续行动没有意义。
    • 不需要ivar,只需检查visible属性,如下面的答案。
    • 我检查了警报视图的 isFirstResponder 是否属实,这也有效。
    • 在提出原始问题时,未公开可见属性。如果现在更正确,请随意投票支持后来的答案,但是从最初的问题到转移到属性(包括可见)之间已经过去了两年。
    【解决方案3】:

    如果您可以控制其他警报视图,请检查每个警报视图的 visible 属性。


    在 iOS 6 或更早版本中,当警报出现时,它会被移动到 _UIAlertOverlayWindow。因此,一个相当脆弱的方法是遍历所有窗口并检查是否有任何 UIAlertView 子视图。

    for (UIWindow* window in [UIApplication sharedApplication].windows) {
      NSArray* subviews = window.subviews;
      if ([subviews count] > 0)
        if ([[subviews objectAtIndex:0] isKindOfClass:[UIAlertView class]])
          return YES;
    }
    return NO;
    

    这是未记录的,因为它取决于内部视图层次结构,尽管 Apple 不能抱怨这一点。一个更可靠但更无证的方法是检查if [_UIAlertManager visibleAlert] is nil

    这些方法无法检查 SpringBoard 中的 UIAlertView 是否显示。

    【讨论】:

    • 代码“UIView* subviews = window.subviews;”中的一个错字应该是 NSArray* subviews = window.subviews;顺便说一句,它对我帮助很大,谢谢。
    • @Deepesh,你找到解决方案了吗?
    • @Jacky,我没有找到任何正确的解决方案...如果您找到任何解决方案...请粘贴您的宝贵答案...。谢谢
    【解决方案4】:
    - (BOOL)checkAlertExist {
        for (UIWindow* window in [UIApplication sharedApplication].windows) {
            NSArray* subviews = window.subviews;
            if ([subviews count] > 0) {
                for (id cc in subviews) {
                    if ([cc isKindOfClass:[UIAlertView class]]) {
                        return YES;
                    }
                }
            }
        }
        return NO;
    }
    

    【讨论】:

    • 这在 iOS 7 中不起作用。第一个子视图可能是一个容器。所以你必须遍历整个可能的树。
    • @Womble,你找到解决办法了吗?
    【解决方案5】:

    另一个适用于整个应用且不涉及遍历视图堆栈的选项是将UIAlertView 子类化为MyUIAlertView,添加静态(类)变量BOOL alertIsShowing,并覆盖-(void)show 选择器。

    在覆盖的 show 选择器中,检查 alertIsShowing 变量。如果是YES,则在延迟后重试(使用dispatch_after 或设置NSTimer)。如果是NO,请继续拨打[super show] 并将YES 分配给alertIsShowing;当警报视图被隐藏时,将alertIsShowing 设置回NO(你需要聪明地处理委托)。

    最后,检查并用MyUIAlertView替换所有UIAlertView实例。

    【讨论】:

    • 我喜欢这个答案(尽管我对UIAlertController 进行了子类化-如果您同时使用两者,我认为您需要同时跟踪两者)。我确实最终使用了计数器而不是布尔值。这样,如果您尝试同时显示两个警报,如果出现/消失方法被调用与您期望的不同步,您就不会意外地将布尔值设置为 false。
    【解决方案6】:

    斯威夫特:

    func showAlert(withTitle title: String, message: String, viewController: UIViewController) {
        if viewController.presentedViewController == nil { // Prevent multiple alerts at the same time
            let localizedTitle = NSLocalizedString(title, comment: "")
            let localizedMessage = NSLocalizedString(message, comment: "")
            let alert = UIAlertController(title: localizedTitle, message: localizedMessage, preferredStyle: .Alert)
            let action = UIAlertAction(title: "OK", style: .Default, handler: nil)
            alert.addAction(action)
    
            viewController.presentViewController(alert, animated: true, completion: nil)
        }
    }
    

    【讨论】:

    • viewntroller.presentedViewController == nil 成功了。谢谢
    【解决方案7】:

    我认为它会起作用:

    -(BOOL) doesAlertViewExist {
        if ([[UIApplication sharedApplication].keyWindow isMemberOfClass:[UIWindow class]])
        {
            return NO;//AlertView does not exist on current window
        }
        return YES;//AlertView exist on current window
    }
    

    【讨论】:

    • 少码-(BOOL) doesAlertViewExist { return ![[UIApplication sharedApplication].keyWindow isMemberOfClass:[UIWindow class]]; }
    【解决方案8】:
    // initialize default flag for alert... If alert is not open set isOpenAlert as NO
    BOOL isAlertOpen;
    isAlertOpen = NO;
    if (isAlertOpen == NO) {
        UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Alert" message:@"Alert is Open" delegate:self cancelButtonTitle:@"Okay!!" otherButtonTitles: nil];
        [alert show];
        // Now set isAlertOpen to YES
        isAlertOpen = YES;
    }
    else
    {
        //Do something
    }
    

    【讨论】:

      【解决方案9】:
      + (BOOL)checkAlertExist {
      
          for (UIWindow* window in [UIApplication sharedApplication].windows) {
              if ([window.rootViewController.presentedViewController isKindOfClass:[UIAlertController class]]) {
                  return YES;
              }
          }
          return NO;
      }
      

      【讨论】:

        【解决方案10】:

        关于我在视图层次结构中查找 UIAlertView 的一些注意事项:

        我尝试循环遍历所有 [UIApplication sharedApplication].windows 视图,但找不到任何东西。

        UIApplication 文档的 windows 属性声明如下:

        此属性包含当前关联的 UIWindow 对象 应用程序。 此列表不包括由 系统,例如用于显示状态栏的窗口。

        所以这让我意识到UIAlertView 所在的UIWindow 甚至没有呈现给我们。

        但是,UIApplication 上还有一个名为 keyWindow 的属性。通过循环,我发现了可以组成警报视图的私有类:

        在 iOS 7 上:_UIModalItemHostingWindow_UIModalItemAlertContentView_UIBackdropEffectView

        在 iOS 8 上:_UIAlertControllerActionView_UIAlertControllerShadowedScrollView_UIBackdropView

        我找不到我展示的UIAlertView,而是一堆在内部组成它的类。 所以要回答最初的问题,您可能可以使用 keyWindow 属性并查看您是否注意到这些类,但您的应用可能会因为尝试检查私有类而被拒绝。

        对于使用适用于 iOS 8 的较新的UIAlertController 的人,可以使用以下方式获取对它的引用: [UIApplication sharedApplication].keyWindow.rootViewController.presentedViewController

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-20
          • 2013-01-22
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多