【问题标题】:Displaying UIAlertViews Sequentially按顺序显示 UIAlertViews
【发布时间】:2011-05-18 13:43:28
【问题描述】:

我有几个 UIAlertViews 我想按顺序显示,并且只有在前一个 UIAlertView 被关闭后才继续显示下一个 UIAlertView(通过用户单击确定)。

我知道 didDismissWithButtonIndex 委托和添加标签,但这并没有太大帮助,因为可能会调用多达 3 个 UIAlertViews,并且不一定每次都以相同的顺序。见代码:

if(condition 1){
    alert1 = // UIAlertView[[.....
    [alert1 show]
}

if(condition 2){
    alert2 = // UIAlertView[[.....
    [alert2 show]
}

if(condition 3){
    alert3 = // UIAlertView[[.....
    [alert3 show]
}

上面只会添加 3 个警报(取决于满足多少条件),这不是我想要的。我希望一次只显示一个,然后在用户点击确定按钮后显示下一个(如果有的话)。

我的想法可能是将消息添加到队列中,然后处理该队列以在每次解除警报时删除警报,但我不确定 id 是如何做到这一点的。

任何想法将不胜感激。 谢谢

【问题讨论】:

    标签: objective-c uiview uialertview alert


    【解决方案1】:

    您可以在 UIAlertView 委托方法中轻松完成此操作,该方法会在警报视图关闭后调用。所以,UIAlertViewDelegate 定义了如下委托方法:

    – alertView:didDismissWithButtonIndex:
    

    实现该方法,并确保您的类是您创建的 UIAlertViews 的委托。此方法是根据用户关闭的警报显示 next 警报的理想场所。

    如果您的要求是“按顺序显示最多三个警报,但不总是以相同的顺序显示”我可能会将警报放入数组中,然后在委托方法中从数组中获取下一个警报显示。它实际上不必比这更复杂。关键是委托方法实现是显示下一个警报的最佳位置。

    伪代码示例:

    定义一个数组; NSMutableArray * alerts_;

    - (void)showAlertSequence {
        if ( !alerts_ ) {
            alerts_ = [[NSMutableArray alloc] init];
        }
    
        [alerts_ addObjects;<My alerts>];
    
        [self showSequencedAlertFrom:nil];
    }
    
    - (BOOL)showSequencedAlertFrom:(UIAlertView *)sourceAlertView {
    
        if ( !sourceAlertView ) {
            [[alerts_ objectAtIndex:0] show];
        }
        else {
            NSInteger index = [alerts_ indexOfObject:sourceAlertView];
    
            if ( index < [alerts_ count] ) {
                [[alerts_ objectAtIndex:index++] show];
            }
        }
    
        return NO;
    }
    
    – alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)index {
    
        // Show the next alert or clean up if we're at the end of the sequence.
        if ( ![self showSequencedAlertFrom:alertView] ) {
            [alerts_ removeAllObjects];
        }
    }   
    

    顺便说一句;三个连续的警报真的会惹恼你的用户;)

    【讨论】:

    • 谢谢@dannywartnaby 这类似于我已经尝试过的东西。问题是在这里你假设所有的 alertViews 都存在。如果只存在 alertView 1 和 3 怎么办?如果是这种情况,您的伪代码将跳过 alert3。还是我遗漏了一些明显的东西?
    • 这种方法的另一个问题是警报 1 不会总是存在,这意味着其他警报都不会显示。这就是为什么我正在考虑对委托方法使用不同的方法。感谢您的回复
    • 好的,我明白了。好吧,我已经稍微更新了我的答案;底线是委托方法是,IMO,决定何时显示下一个警报的最佳位置。如果您不能始终如一地知道正在显示哪些警报以及以什么顺序显示,那么 IMO 将您要显示的警报放入一个集合中,然后在委托方法中迭代该集合,获得“下一个”是有意义的基于当前。
    • 再次感谢!这似乎更符合逻辑。我试图实现这一点,但是当我关闭第一个 alertView 时,控制台返回:wait_fences: failed to receive reply: 10004003 message。应用程序停止。我看不出有什么明显的原因可能导致这种情况。再次感谢您的帮助,我想我快到了!
    【解决方案2】:

    我做过的一件事是通过在 AlertView 上添加类别来使用基于块的 UIAlertViews。

    这是.h文件

    @interface UIAlertView (WithBlocks)
    
    - (id) initWithTitle:(NSString *)title message:(NSString *)message;
    - (void) addButtonWithTitle:(NSString *)title andBlock:(void(^)())block;
    
    @end
    

    这是.m文件

    static NSString *BUTTON_BLOCK_KEY = @"alertview-button-blocks";
    
    @interface UIAlertView()
    - (void) runBlock: (void (^)())block;
    @end
    
    @implementation UIAlertView (WithBlocks)
    
    /**
     * Initialized an alert view with a title and message.
     */
    - (id) initWithTitle:(NSString *)title message:(NSString *)message
    {
        self = [self initWithTitle:title message:message delegate:nil cancelButtonTitle:nil otherButtonTitles:nil];
        if (self) {
            self.delegate = self;
            NSMutableArray *buttonBlocks = [NSMutableArray array];
            objc_setAssociatedObject(self, BUTTON_BLOCK_KEY, buttonBlocks, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
    
        }
        return self;
    }
    
    /**
     * Adds a button with a title and a block to be executed when that button is tapped.
     */
    - (void) addButtonWithTitle:(NSString *)title andBlock:(void (^)())block
    {
        // Add the button
        [self addButtonWithTitle:title];
        NSMutableArray *buttonBlocks = objc_getAssociatedObject(self, BUTTON_BLOCK_KEY);
        if (!block) {
            block = ^{ /* empty block */ };
        }
        [buttonBlocks addObject:[[[block copy] retain] autorelease]];
    }
    
    - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
    {
        NSMutableArray *buttonBlocks = objc_getAssociatedObject(self, BUTTON_BLOCK_KEY);
        void (^block)() = (void (^)()) [buttonBlocks objectAtIndex:buttonIndex];
    
        // Due to a timing issue, the current window is still the UIAlertView for a very
        // short amount of time after it has been dismissed which messes up anything
        // trying to get the current window in the blocks being run.
        // Ergo, the block is being delayed by a tiny bit. (Amount determined through limited testing)
        [self performSelector:@selector(runBlock:) withObject:block afterDelay:0.25];
    }
    
    - (void) runBlock: (void (^)())block
    {
        block();
    }
    
    @end
    

    然后你可以通过下面的代码调用链式的alertviews

     void(^continueBlock)(void) = ^{
         // Display more alertviews here
     };
    
     UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Title" message:@"message"];
     [alert addButtonWithTitle:@"Continue" andBlock:continueBlock];
    
     [alert addButtonWithTitle:@"Dismiss" andBlock:^{
       // Display more alertviews here
     }
     [alert show];
     [alert release];
    

    【讨论】:

      【解决方案3】:

      我也在寻找解决这个问题的方法。这是我最终为自己的应用解决它的方式:

      static BOOL alertShowing = FALSE;
      
      UIAlertView *alert0 = [[UIAlertView alloc] initWithTitle:@"AlertView 0" message:@"This is the first alert" delegate:self cancelButtonTitle:nil otherButtonTitles:@"Yes",@"No", nil];
      [alert0 setTag:0];
      alertShowing = TRUE;
      [alert0 show];
      
      while (alertShowing) { 
          [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.2]];
      }
      
      UIAlertView *alert1 = [[UIAlertView alloc] initWithTitle:@"AlertView 1" message:@"This is the second alert" delegate:self cancelButtonTitle:nil otherButtonTitles:@"Yes",@"No", nil];
      [alert1 setTag:1];
      alertShowing = TRUE;
      [alert1 show];
      
      while (alertShowing) { 
          [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate dateWithTimeIntervalSinceNow:0.2]];
      }
      
      // add some more alerts here for dramatic effect ...
      

      您的按钮处理程序必须在每个退出路径中设置alertShowing = FALSE'

      - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
          // Deal with handling responses for your different alerts here.
          switch ([alertView tag]) {
              case 0:
                  // handler first alert here
                  break;
              case 1:
                  // handler second alert here
                  break;
              default:
                  // etc.
                  break;
          }
      
          alertShowing = FALSE;
      }
      

      可能有比创建一个新的运行循环更好的坐下来旋转的方法,并且有一些重复的代码可能可以更好地通用化。从好的方面来说,它很简单,不需要一堆排队逻辑。我为这种模式使用了#define 来避免手动输入它,并且在我的情况下它运行良好。

      【讨论】:

        【解决方案4】:

        这就是我按照您的建议使用警报队列的方法。

        @property (strong, nonatomic) NSMutableArray *alertQueue;
        @property (nonatomic) BOOL showingAlert;
        
        - (void)showAlert:(UIAlertView *)alert {
          if (self.showingAlert) {
            [self.alertQueue addObject:alert];
          }
          else {
            self.showingAlert = YES;
            [alert show];
          }
        }
        
        - (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
        {
          if ([self.alertQueue count]) {
            UIAlertView *alert = [self.alertQueue objectAtIndex:0];
            [self.alertQueue removeObjectAtIndex:0];
            [alert show];
          }
          else self.showingAlert = NO;
        }
        

        然后,每当您想显示警报时,您只需创建 UIAlertView 并将其传递给 showAlert 方法,它只会在所有早期警报都被解除后才会显示。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2020-10-31
          • 1970-01-01
          • 2018-03-26
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2014-04-01
          相关资源
          最近更新 更多