iOS 使用信号量控制多个presentViewController方法短时间内并发

最近在项目中遇到一个问题, 当一个提示页面是用present弹出并且带动画时,一个个分别弹出没有问题.但是当需要同时弹出页面并且一个叠一个时就会导致presentViewController丢失页面,原因是当上一个页面弹出还未执行完成的时候,下一个页面present就无法真正的弹出.
这边我写一下我的解决方案
1.首先创建一个类继承UINavigationController,在项目中这个类是我的window.rootViewController.
#import 
@interface RootNavigationVController : UINavigationController
@property (nonatomic, strong) dispatch_semaphore_t signal;
@end

如以上代码所示为RootNavigationVController 添加dispatch_semaphore_t 后续我们使用信号量的方式来控制presentViewController的弹出.

2. 重写- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)())completion 方法:
- (void)presentViewController:(UIViewController *)viewControllerToPresent animated:(BOOL)flag completion:(void (^)())completion {
      //初始化信号量,最高并发执行 1
      if (!self.signal) {
          self.signal = dispatch_semaphore_create(1);
      }

      dispatch_async(dispatch_get_global_queue(0, 0), ^{
          //当present被调用时, wait -1,此时信号量为0,其他执行等待
          dispatch_semaphore_wait(self.signal, dispatch_time(DISPATCH_TIME_NOW, 5 * NSEC_PER_SEC));
          dispatch_async(dispatch_get_main_queue(), ^{
               //判断是否是modal视图
               if (self.presentedViewController) {
                    UIViewController *vc = self.presentedViewController;
                    while (vc.presentedViewController) {
                         vc = vc.presentedViewController;
                    }
                    //取栈顶的modal视图来执行
                    [vc presentViewController:viewControllerToPresent animated:flag completion:^{
                         dispatch_semaphore_signal(self.signal); //弹窗完成信号量 +1 允许下一次弹窗任务执行
                         if (completion) {
                            completion();
                          }
                     }];
               } else { //同上
                     [super presentViewController:viewControllerToPresent animated:flag completion:^{
                           dispatch_semaphore_signal(self.signal);
                           if (completion) {
                              completion();
                            }
                      }];
               }
          });
    });
}

这边主要就是使用信号量在进入presentViewContrller的时候对线程进行阻塞, 在并发的时候让下一个执行等待.然后completion 的block里面弹窗完成,将信号量+1,允许下一个页面执行.同时判断上一个页面类型使用不同方法进行弹窗. 这边我dispatch_semaphore_wait 的timeout设置是5秒,不同业务根据需求设置即可.

3.在业务中使用时:
[self.navigationController presentViewController:vc animated:YES completion:nil];

这样不会影响原有其他地方的presentViewController方法,使用上也没有其他变化.

你可能感兴趣的:(iOS 使用信号量控制多个presentViewController方法短时间内并发)